diff --git a/en_US.ISO8859-1/books/arch-handbook/jail/chapter.sgml b/en_US.ISO8859-1/books/arch-handbook/jail/chapter.sgml
index 1f465a8145..29138c5ca1 100644
--- a/en_US.ISO8859-1/books/arch-handbook/jail/chapter.sgml
+++ b/en_US.ISO8859-1/books/arch-handbook/jail/chapter.sgml
@@ -1,755 +1,755 @@
Evan
Sarmiento
evms@cs.bu.edu
2001
Evan Sarmiento
The Jail Subsystem
security
Jail
root
On most &unix; systems, root has omnipotent power.
This promotes insecurity. If an attacker gained root
on a system, he would have every function at his fingertips. In FreeBSD
there are sysctls which dilute the power of root, in
order to minimize the damage caused by an attacker. Specifically, one of
these functions is called secure levels. Similarly,
another function which is present from FreeBSD 4.0 and onward, is a utility
called &man.jail.8;. Jail chroots an environment
and sets certain restrictions on processes which are forked within
the jail. For example, a jailed process
cannot affect processes outside the jail,
utilize certain system calls, or inflict any damage on the host
environment.
Jail is becoming the new security
model. People are running potentially vulnerable servers such as
Apache, BIND, and
sendmail within jails, so that if an attacker
gains root within the jail,
it is only an annoyance, and not a devastation. This article mainly
focuses on the internals (source code) of jail.
If you are looking for a how-to on setting up a
jail, I suggest you look at my other article
in Sys Admin Magazine, May 2001, entitled "Securing FreeBSD using
Jail."
Architecture
Jail 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 jail is implemented within
the kernel.
Userland Code
Jail
Userland Program
The source for the userland jail
is located in /usr/src/usr.sbin/jail,
consisting of one file, jail.c. The program
takes these arguments: the path of the jail,
hostname, IP address, and the command to be executed.
Data Structures
In jail.c, the first thing I would
note is the declaration of an important structure
struct jail j; which was included from
/usr/include/sys/jail.h.
The definition of the jail structure is:
/usr/include/sys/jail.h:
struct jail {
u_int32_t version;
char *path;
char *hostname;
u_int32_t ip_number;
};
As you can see, there is an entry for each of the
arguments passed to the &man.jail.8; program, and indeed,
they are set during its execution.
/usr/src/usr.sbin/jail/jail.c
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];
Networking
One of the arguments passed to the &man.jail.8; program is
an IP address with which the jail
can be accessed over the network. &man.jail.8; translates the
IP address given into host byte order and then stores it in
j (the jail structure).
/usr/src/usr.sbin/jail/jail.c:
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);
The &man.inet.aton.3; function "interprets the specified
character string as an Internet address, placing the address
into the structure provided." The ip_number
member in the jail structure is set only
when the IP address placed onto the in
structure by &man.inet.aton.3; is translated into host byte
order by &man.ntohl.3;.
Jailing The Process
Finally, the userland program jails the process.
Jail now becomes an imprisoned
process itself and then executes the command given using
&man.execv.3;.
/usr/src/usr.sbin/jail/jail.c
i = jail(&j);
...
if (execv(argv[3], argv + 3) != 0)
err(1, "execv: %s", argv[3]);
As you can see, the jail() function is
called, and its argument is the jail structure
which has been filled with the arguments given to the program.
Finally, the program you specify is executed. I will now discuss
how jail is implemented within the
kernel.
Kernel Space
Jail
Kernel Architecture
We will now be looking at the file
/usr/src/sys/kern/kern_jail.c. This is
the file where the &man.jail.2; system call, appropriate sysctls,
and networking functions are defined.
sysctls
sysctl
In kern_jail.c, the following
sysctls are defined:
/usr/src/sys/kern/kern_jail.c:
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");
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
security.jail.set_hostname_allowed.
&man.jail.2; system call
Like all system calls, the &man.jail.2; system call takes
two arguments, struct thread *td and
struct jail_args *uap.
td is a pointer to the thread
structure which describes the calling thread. In this
context, uap is a pointer to the structure
in which a pointer to the jail structure
passed by the userland jail.c is contained.
When I described the userland program before, you saw that the
&man.jail.2; system call was given a jail
structure as its own argument.
/usr/src/sys/kern/kern_jail.c:
/*
* struct jail_args {
* struct jail *jail;
* };
*/
int
jail(struct thread *td, struct jail_args *uap)
Therefore, uap->jail can be used to
access the jail structure which was passed
to the system call. Next, the system call copies the
jail 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,
uap->jail, where to store it,
j and the size of the storage. The
jail structure pointed by
uap->jail is copied into kernel space and
is stored in another jail structure,
j.
/usr/src/sys/kern/kern_jail.c:
error = copyin(uap->jail, &j, sizeof(j));
There is another important structure defined in
jail.h. It is the prison
structure. The prison structure is used
exclusively within kernel space. Here is the definition of the
prison structure.
/usr/include/sys/jail.h:
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 */
};
The &man.jail.2; system call then allocates memory for
a prison structure and copies data between
the jail and prison
structure.
/usr/src/sys/kern/kern_jail.c:
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;
Next, we will discuss another important system call
&man.jail.attach.2;, which implements the function to put
a process into the jail.
/usr/src/sys/kern/kern_jail.c:
/*
* struct jail_attach_args {
* int jid;
* };
*/
int
jail_attach(struct thread *td, struct jail_attach_args *uap)
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.
On FreeBSD, each kernel visible thread is identified by its
thread structure, while the processes are
described by their proc structures. You can
find the definitions of the thread and
proc structure in
/usr/include/sys/proc.h.
For example, the td argument in any system
call is actually a pointer to the calling thread's
thread structure, as stated before.
The td_proc member in the
thread structure pointed by td
is a pointer to the proc structure which
represents the process that contains the thread represented by
td. The proc structure
contains members which can describe the owner's
identity(p_ucred), the process resource
limits(p_limit), and so on. In the
ucred structure pointed by
p_ucred member in the proc
structure, there is a pointer to the prison
structure(cr_prison).
/usr/include/sys/proc.h:
struct thread {
...
struct proc *td_proc;
...
};
struct proc {
...
struct ucred *p_ucred;
...
};
/usr/include/sys/ucred.h
struct ucred {
...
struct prison *cr_prison;
...
};
In kern_jail.c, the function
jail() then calls function
jail_attach() with a given jid.
And jail_attach() calls function
change_root() to change the root directory of the
calling process. The jail_attach() then creates
a new ucred structure, and attaches the newly
created ucred structure to the calling process
after it has successfully attached the prison
structure to the ucred structure. From then on,
the calling process is recognized as jailed. When the kernel routine
jailed() is called in the kernel with the newly
created ucred structure as its argument, it
returns 1 to tell that the credential is connected
with a jail. The public ancestor process
of all the process forked within the jail,
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
ucred structure, therefore it has a jailed
ucred structure.
/usr/src/sys/kern/kern_jail.c
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;
...
}
When a process is forked from its parent process, the
&man.fork.2; system call uses crhold() 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.
/usr/src/sys/kern/kern_fork.c:
p2->p_ucred = crhold(td->td_ucred);
...
td2->td_ucred = crhold(p2->p_ucred);
Restrictions
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:
if (jailed(td->td_ucred))
return (EPERM);
SysV IPC
System V IPC
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
jail. One of these sysctls was
security.jail.sysvipc_allowed. By default,
this sysctl is set to 0. If it were set to 1, it would defeat the
whole purpose of having a jail; privileged
users from the jail 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.
/usr/src/sys/kern/sysv_msg.c:
msgget(key, msgflg):
msgget returns (and possibly creates) a message
descriptor that designates a message queue for use in other
functions.
msgctl(msgid, cmd, buf):
Using this function, a process can query the status of a message
descriptor.
msgsnd(msgid, msgp, msgsz, msgflg):
msgsnd sends a message to a
process.
msgrcv(msgid, msgp, msgsz, msgtyp,
msgflg): a process receives messages using
this function
In each of the system calls corresponding to these functions,
there is this conditional:
/usr/src/sys/kern/sysv_msg.c:
if (!jail_sysvipc_allowed && jailed(td->td_ucred))
return (ENOSYS);
semaphores
Semaphore system calls allow processes to synchronize
execution by doing a set of operations atomically on a set of
semaphores. Basically semaphores provide another way for
processes lock resources. However, process waiting on a
semaphore, that is being used, will sleep until the resources
are relinquished. The following semaphore system calls are
blocked inside a jail: &man.semget.2;,
&man.semctl.2; and &man.semop.2;.
/usr/src/sys/kern/sysv_sem.c:
semctl(semid, semnum, cmd, ...):
semctl does the specified cmd
on the semaphore queue indicated by
semid.
semget(key, nsems, flag):
semget creates an array of semaphores,
corresponding to key.
key and flag take on the same meaning as they
do in msgget.
semop(semid, array, nops):
semop performs a group of operations indicated
by array, to the set of semaphores identified by
semid.
shared memory
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;.
/usr/src/sys/kern/sysv_shm.c:
shmctl(shmid, cmd, buf):
shmctl does various control operations on the
shared memory region identified by
shmid.
shmget(key, size, flag):
shmget accesses or creates a shared memory
region of size bytes.
shmat(shmid, addr, flag):
shmat attaches a shared memory region identified
by shmid to the address space of a
process.
shmdt(addr):
shmdt detaches the shared memory region
previously attached at addr.
Sockets
sockets
Jail 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
security.jail.socket_unixiproute_only is set. If
set, sockets are only allowed to be created if the family
specified is either PF_LOCAL,
PF_INET or
PF_ROUTE. Otherwise, it returns an
error.
/usr/src/sys/kern/uipc_socket.c:
int
socreate(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);
}
...
}
Berkeley Packet Filter
Berkeley Packet Filter
data link layer
The Berkeley Packet Filter provides
a raw interface to data link layers in a protocol independent
fashion. BPF is now controlled by the
&man.devfs.8; whether it can be used in a jailed environment.
Protocols
protocols
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 nam
parameter is set. nam is a pointer to a
sockaddr structure,
which describes the address on which to bind the service. A
more exact definition is that sockaddr "may be
used as a template for referring to the identifying tag and length of
each address". In the function
in_pcbbind_setup(), sin is a
pointer to a sockaddr_in structure, which
contains the port, address, length and domain family of the socket
which is to be bound. Basically, this disallows any processes from
jail to be able to specify the address
that doesn't belong to the jail in which
the calling process exists.
/usr/src/sys/netinet/in_pcb.c:
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);
...
}
You might be wondering what function
prison_ip() does. prison_ip()
is given three arguments, a pointer to the credential(represented by
cred), any flags, and an IP address. It
returns 1 if the IP address does NOT belong to the
jail or 0 otherwise. As you can see
from the code, if it is indeed an IP address not belonging to the
- jail, the protcol is not allowed to bind
+ jail, the protocol is not allowed to bind
to that address.
/usr/src/sys/kern/kern_jail.c:
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);
}
Filesystem
filesystem
Even root users within the
jail 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.
/usr/src/sys/ufs/ufs/ufs_vnops.c:
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);
}
...
}
}
/usr/src/sys/kern/kern_priv.c
int
priv_check_cred(struct ucred *cred, int priv, int flags)
{
...
error = prison_priv_check(cred, priv);
if (error)
return (error);
...
}
/usr/src/sys/kern/kern_jail.c
int
prison_priv_check(struct ucred *cred, int priv)
{
...
switch (priv) {
...
case PRIV_VFS_SYSFLAGS:
if (jail_chflags_allowed)
return (0);
else
return (EPERM);
...
}
...
}
diff --git a/en_US.ISO8859-1/books/arch-handbook/mac/chapter.sgml b/en_US.ISO8859-1/books/arch-handbook/mac/chapter.sgml
index 10e2089e2e..14c2f00542 100644
--- a/en_US.ISO8859-1/books/arch-handbook/mac/chapter.sgml
+++ b/en_US.ISO8859-1/books/arch-handbook/mac/chapter.sgml
@@ -1,8028 +1,8028 @@
Chris
Costello
TrustedBSD Project
chris@FreeBSD.org
Robert
Watson
TrustedBSD Project
rwatson@FreeBSD.org
The TrustedBSD MAC Framework
MAC Documentation Copyright
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 (CBOSS
), as part of the DARPA
CHATS research program.
Redistribution and use in source (SGML DocBook) and
'compiled' forms (SGML, HTML, PDF, PostScript, RTF and so forth)
with or without modification, are permitted provided that the
following conditions are met:
Redistributions of source code (SGML DocBook) must
retain the above copyright notice, this list of conditions
and the following disclaimer as the first lines of this file
unmodified.
Redistributions in compiled form (transformed to other
DTDs, converted to PDF, PostScript, RTF and other formats)
must reproduce the above copyright notice, this list of
conditions and the following disclaimer in the documentation
and/or other materials provided with the
distribution.
THIS DOCUMENTATION IS PROVIDED BY THE NETWORKS ASSOCIATES
TECHNOLOGY, INC "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL NETWORKS ASSOCIATES TECHNOLOGY,
INC BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS DOCUMENTATION, EVEN
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Synopsis
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.
This chapter introduces the MAC policy framework and
provides documentation for a sample MAC policy module.
Introduction
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.
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.
Policy Background
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.
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.
MAC Framework Kernel Architecture
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.
Kernel Elements
The MAC Framework contains a number of kernel elements:
Framework management interfaces
Concurrency and synchronization
primitives.
Policy registration
Extensible security label for kernel
objects
Policy entry point composition
operators
Label management primitives
Entry point API invoked by kernel
services
Entry point API to policy modules
Entry points implementations (policy life cycle,
object life cycle/label management, access control
checks).
Policy-agnostic label-management system
calls
mac_syscall() multiplex
system call
Various security policies implemented as MAC
policy modules
Framework Management Interfaces
The TrustedBSD MAC Framework may be directly managed using
sysctl's, loader tunables, and system calls.
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.
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.
Policy List Concurrency and Synchronization
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.
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.
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.
Label Synchronization
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.
Policy Synchronization and Concurrency
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.
- When policy modules call out to other kernel subsytems,
+ 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.
Policy Registration
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 SYSINIT to invoke a registration
function; when a policy module is unloaded,
SYSINIT will likewise invoke a
de-registration function. Registration may fail if a
policy module is loaded more than once, if insufficient
resources are available for the registration (for
example, the policy might require labeling and
insufficient labeling state might be available), or
other policy prerequisites might not be met (some
policies may only be loaded prior to boot). Likewise,
de-registration may fail if a policy is flagged as
not unloadable.
Entry Points
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.
Policy Composition
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.
Labeling Support
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.
In-memory labels are stored in slab-allocated struct
label, which consists of a fixed-length array
of unions, each holding a void * pointer
and a long. Policies registering for
label storage will be assigned a "slot" identifier, which
may be used to dereference the label storage. The semantics
of the storage are left entirely up to the policy module:
modules are provided with a variety of entry points
associated with the kernel object life cycle, including
initialization, association/creation, and destruction. Using
these interfaces, it is possible to implement reference
counting and other storage 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.
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.
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 (v_label) 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.
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.
System Calls
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.
The label management calls accept a label description
structure, struct mac, which
contains a series of MAC label elements. Each element
contains a character string name, and character string
value. Each policy will be given the chance to claim a
particular element name, permitting policies to expose
multiple independent elements if desired. Policy modules
perform the internalization and externalization between
kernel labels and user-provided labels via entry points,
permitting a variety of semantics. Label management system
calls are generally wrapped by user library functions to
perform memory allocation and error handling, simplifying
user applications that must manage labels.
The following MAC-related system calls are present in the
FreeBSD kernel:
mac_get_proc() may be used to
retrieve the label of the current process.
mac_set_proc() may be used to request
a change in the label of the current process.
mac_get_fd() may be used to retrieve
the label of an object (file, socket, pipe, ...) referenced by a
file descriptor.
mac_get_file() may be used to retrieve
the label of an object referenced by a file system path.
mac_set_fd() may be used to request
a change in the label of an object (file, socket, pipe, ...)
referenced by a file descriptor.
mac_set_file() may be used to request
a change in the label of an object referenced by a file system
path.
mac_syscall() 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.
mac_get_pid() may be used to request
the label of another process by process id.
mac_get_link() is identical to
mac_get_file(), 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.
mac_set_link() is identical to
mac_set_file(), 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.
mac_execve() is identical to the
execve() 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".
mac_get_peer(), actually implemented
via a socket option, retrieves the label of a remote peer on a
socket, if available.
In addition to these system calls, the
SIOCSIGMAC and SIOCSIFMAC
network interface ioctls permit the labels on network interfaces to
be retrieved and set.
MAC Policy Architecture
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:
Optional configuration parameters for
policy.
Centralized implementation of the policy
logic and parameters.
Optional implementation of policy life cycle
events, such as initialization and destruction.
Optional support for initializing, maintaining, and
destroying labels on selected kernel objects.
Optional support for user process inspection and
modification of labels on selected objects.
Implementation of selected access control
entry points that are of interest to the policy.
Declaration of policy identity, module entry
points, and policy properties.
Policy Declaration
Modules may be declared using the
MAC_POLICY_SET() macro, which names the
policy, provides a reference to the MAC entry point vector,
provides load-time flags determining how the policy framework
should handle the policy, and optionally requests the
allocation of label state by the framework.
static struct mac_policy_ops mac_policy_ops =
{
.mpo_destroy = mac_policy_destroy,
.mpo_init = mac_policy_init,
.mpo_init_bpfdesc_label = mac_policy_init_bpfdesc_label,
.mpo_init_cred_label = mac_policy_init_label,
/* ... */
.mpo_check_vnode_setutimes = mac_policy_check_vnode_setutimes,
.mpo_check_vnode_stat = mac_policy_check_vnode_stat,
.mpo_check_vnode_write = mac_policy_check_vnode_write,
};
The MAC policy entry point vector,
mac_policy_ops in this example, associates
functions defined in the module with specific entry points. A
complete listing of available entry points and their
prototypes may be found in the MAC entry point reference
section. Of specific interest during module registration are
the .mpo_destroy and .mpo_init
entry points. .mpo_init will be invoked once a
policy is successfully registered with the module framework
but prior to any other entry points becoming active. This
permits the policy to perform any policy-specific allocation
and initialization, such as initialization of any data or
locks. .mpo_destroy will be invoked when a
policy module is unloaded to permit releasing of any allocated
memory and destruction of locks. Currently, these two entry
points are invoked with the MAC policy list mutex held to
prevent any other entry points from being invoked: this will
be changed, but in the mean time, policies should be careful
about what kernel primitives they invoke so as to avoid lock
ordering or sleeping problems.
The policy declaration's module name field exists so that
the module may be uniquely identified for the purposes of
module dependencies. An appropriate string should be selected.
The full string name of the policy is displayed to the user
via the kernel log during load and unload events, and also
exported when providing status information to userland
processes.
Policy Flags
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:
MPC_LOADTIME_FLAG_UNLOADOK
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.
MPC_LOADTIME_FLAG_NOTLATE
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.
MPC_LOADTIME_FLAG_LABELMBUFS
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,
MAC_ALWAYS_LABEL_MBUF, exists to
force the MAC Framework to allocate Mbuf label storage
regardless of the setting of this flag, and may be
useful in some environments.
Policies using the
MPC_LOADTIME_FLAG_LABELMBUFS without the
MPC_LOADTIME_FLAG_NOTLATE flag set
must be able to correctly handle NULL
Mbuf label pointers passed into entry points. This is necessary
as in-flight Mbufs without label storage may persist after a
policy enabling Mbuf labeling has been loaded. If a policy
is loaded before the network subsystem is active (i.e., the
policy is not being loaded late), then all Mbufs are guaranteed
to have label storage.
Policy Entry Points
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 mac_syscall() entry point is
provided so that policies may extend the kernel interface
without registering new system calls.
Policy module writers should be aware of the kernel
locking strategy, as well as what object locks are available
during which entry points. Writers should attempt to avoid
deadlock scenarios by avoiding grabbing non-leaf locks inside
of entry points, and also follow the locking protocol for
object access and modification. In particular, writers should
be aware that while necessary locks to access objects and
their labels are generally held, sufficient locks to modify an
object or its label may not be present for all entry points.
Locking information for arguments is documented in the MAC
framework entry point document.
Policy entry points will pass a reference to the object
label along with the object itself. This permits labeled
policies to be unaware of the internals of the object yet
still make decisions based on the label. The exception to this
is the process credential, which is assumed to be understood
by policies as a first class security object in the kernel.
MAC Policy Entry Point Reference
General-Purpose Module Entry Points
&mac.mpo;_init
void
&mac.mpo;_init
struct mac_policy_conf
*conf
&mac.thead;
conf
MAC policy definition
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().
&mac.mpo;_destroy
void
&mac.mpo;_destroy
struct mac_policy_conf
*conf
&mac.thead;
conf
MAC policy definition
Policy load event. The policy list mutex is held, so
caution should be applied.
&mac.mpo;_syscall
int
&mac.mpo;_syscall
struct thread
*td
int call
void *arg
&mac.thead;
td
Calling thread
call
Policy-specific syscall number
arg
Pointer to syscall arguments
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.
Modules must currently perform the
copyin() of the syscall data on their
own.
&mac.mpo;_thread_userret
void
&mac.mpo;_thread_userret
struct thread
*td
&mac.thead;
td
Returning thread
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
p_label protected by a per-policy spin
lock, and then set the per-thread
TDF_ASTPENDING flag and per-process
PS_MACPENDM 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.
Label Operations
&mac.mpo;_init_bpfdesc_label
void
&mac.mpo;_init_bpfdesc_label
struct label
*label
&mac.thead;
label
New label to apply
Initialize the label on a newly instantiated bpfdesc (BPF
descriptor). Sleeping is permitted.
&mac.mpo;_init_cred_label
void
&mac.mpo;_init_cred_label
struct label
*label
&mac.thead;
label
New label to initialize
Initialize the label for a newly instantiated
user credential. Sleeping is permitted.
&mac.mpo;_init_devfsdirent_label
void
&mac.mpo;_init_devfsdirent_label
struct label
*label
&mac.thead;
label
New label to apply
Initialize the label on a newly instantiated devfs
entry. Sleeping is permitted.
&mac.mpo;_init_ifnet_label
void
&mac.mpo;_init_ifnet_label
struct label
*label
&mac.thead;
label
New label to apply
Initialize the label on a newly instantiated network
interface. Sleeping is permitted.
&mac.mpo;_init_ipq_label
void
&mac.mpo;_init_ipq_label
struct label
*label
int flag
&mac.thead;
label
New label to apply
flag
Sleeping/non-sleeping &man.malloc.9;; see
below
Initialize the label on a newly instantiated IP fragment
reassembly queue. The flag field may
be one of M_WAITOK and M_NOWAIT,
and should be employed to avoid performing a 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.
&mac.mpo;_init_mbuf_label
void
&mac.mpo;_init_mbuf_label
int flag
struct label
*label
&mac.thead;
flag
Sleeping/non-sleeping &man.malloc.9;; see
below
label
Policy label to initialize
Initialize the label on a newly instantiated mbuf packet
header (mbuf). The
flag field may be one of
M_WAITOK and M_NOWAIT, and
should be employed to avoid performing a 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.
&mac.mpo;_init_mount_label
void
&mac.mpo;_init_mount_label
struct label
*mntlabel
struct label
*fslabel
&mac.thead;
mntlabel
Policy label to be initialized for the mount
itself
fslabel
Policy label to be initialized for the file
system
Initialize the labels on a newly instantiated mount
point. Sleeping is permitted.
&mac.mpo;_init_mount_fs_label
void
&mac.mpo;_init_mount_fs_label
struct label
*label
&mac.thead;
label
Label to be initialized
Initialize the label on a newly mounted file
system. Sleeping is permitted
&mac.mpo;_init_pipe_label
void
&mac.mpo;_init_pipe_label
struct
label*label
&mac.thead;
label
Label to be filled in
Initialize a label for a newly instantiated pipe. Sleeping
is permitted.
&mac.mpo;_init_socket_label
void
&mac.mpo;_init_socket_label
struct label
*label
int flag
&mac.thead;
label
New label to initialize
flag
&man.malloc.9; flags
Initialize a label for a newly instantiated
socket. The flag field may be one of
M_WAITOK and M_NOWAIT, and
should be employed to avoid performing a sleeping &man.malloc.9;
during this initialization call.
&mac.mpo;_init_socket_peer_label
void
&mac.mpo;_init_socket_peer_label
struct label
*label
int flag
&mac.thead;
label
New label to initialize
flag
&man.malloc.9; flags
Initialize the peer label for a newly instantiated
socket. The flag field may be one of
M_WAITOK and M_NOWAIT, and
should be employed to avoid performing a sleeping &man.malloc.9;
during this initialization call.
&mac.mpo;_init_proc_label
void
&mac.mpo;_init_proc_label
struct label
*label
&mac.thead;
label
New label to initialize
Initialize the label for a newly instantiated
process. Sleeping is permitted.
&mac.mpo;_init_vnode_label
void
&mac.mpo;_init_vnode_label
struct label
*label
&mac.thead;
label
New label to initialize
Initialize the label on a newly instantiated vnode. Sleeping
is permitted.
&mac.mpo;_destroy_bpfdesc_label
void
&mac.mpo;_destroy_bpfdesc_label
struct label
*label
&mac.thead;
label
bpfdesc label
Destroy the label on a BPF descriptor. In this entry
point a policy should free any internal storage associated
with label so that it may be
destroyed.
&mac.mpo;_destroy_cred_label
void
&mac.mpo;_destroy_cred_label
struct label
*label
&mac.thead;
label
Label being destroyed
Destroy the label on a credential. In this entry point,
a policy module should free any internal storage associated
with label so that it may be
destroyed.
&mac.mpo;_destroy_devfsdirent_label
void
&mac.mpo;_destroy_devfsdirent_label
struct label
*label
&mac.thead;
label
Label being destroyed
Destroy the label on a devfs entry. In this entry
point, a policy module should free any internal storage
associated with label so that it may
be destroyed.
&mac.mpo;_destroy_ifnet_label
void
&mac.mpo;_destroy_ifnet_label
struct label
*label
&mac.thead;
label
Label being destroyed
Destroy the label on a removed interface. In this entry
point, a policy module should free any internal storage
associated with label so that it may
be destroyed.
&mac.mpo;_destroy_ipq_label
void
&mac.mpo;_destroy_ipq_label
struct label
*label
&mac.thead;
label
Label being destroyed
Destroy the label on an IP fragment queue. In this
entry point, a policy module should free any internal
storage associated with label so that
it may be destroyed.
&mac.mpo;_destroy_mbuf_label
void
&mac.mpo;_destroy_mbuf_label
struct label
*label
&mac.thead;
label
Label being destroyed
Destroy the label on an mbuf header. In this entry
point, a policy module should free any internal storage
associated with label so that it may
be destroyed.
&mac.mpo;_destroy_mount_label
void
&mac.mpo;_destroy_mount_label
struct label
*label
&mac.thead;
label
Mount point label being destroyed
Destroy the labels on a mount point. In this entry
point, a policy module should free the internal storage
associated with mntlabel so that they
may be destroyed.
&mac.mpo;_destroy_mount_label
void
&mac.mpo;_destroy_mount_label
struct label
*mntlabel
struct label
*fslabel
&mac.thead;
mntlabel
Mount point label being destroyed
fslabel
File system label being destroyed>
Destroy the labels on a mount point. In this entry
point, a policy module should free the internal storage
associated with mntlabel and
fslabel so that they may be
destroyed.
&mac.mpo;_destroy_socket_label
void
&mac.mpo;_destroy_socket_label
struct label
*label
&mac.thead;
label
Socket label being destroyed
Destroy the label on a socket. In this entry point, a
policy module should free any internal storage associated
with label so that it may be
destroyed.
&mac.mpo;_destroy_socket_peer_label
void
&mac.mpo;_destroy_socket_peer_label
struct label
*peerlabel
&mac.thead;
peerlabel
Socket peer label being destroyed
Destroy the peer label on a socket. In this entry
point, a policy module should free any internal storage
associated with label so that it may
be destroyed.
&mac.mpo;_destroy_pipe_label
void
&mac.mpo;_destroy_pipe_label
struct label
*label
&mac.thead;
label
Pipe label
Destroy the label on a pipe. In this entry point, a
policy module should free any internal storage associated
with label so that it may be
destroyed.
&mac.mpo;_destroy_proc_label
void
&mac.mpo;_destroy_proc_label
struct label
*label
&mac.thead;
label
Process label
Destroy the label on a process. In this entry point, a
policy module should free any internal storage associated
with label so that it may be
destroyed.
&mac.mpo;_destroy_vnode_label
void
&mac.mpo;_destroy_vnode_label
struct label
*label
&mac.thead;
label
Process label
Destroy the label on a vnode. In this entry point, a
policy module should free any internal storage associated
with label so that it may be
destroyed.
&mac.mpo;_copy_mbuf_label
void
&mac.mpo;_copy_mbuf_label
struct label
*src
struct label
*dest
&mac.thead;
src
Source label
dest
Destination label
Copy the label information in
src into
dest.
&mac.mpo;_copy_pipe_label
void
&mac.mpo;_copy_pipe_label
struct label
*src
struct label
*dest
&mac.thead;
src
Source label
dest
Destination label
Copy the label information in
src into
dest.
&mac.mpo;_copy_vnode_label
void
&mac.mpo;_copy_vnode_label
struct label
*src
struct label
*dest
&mac.thead;
src
Source label
dest
Destination label
Copy the label information in
src into
dest.
&mac.mpo;_externalize_cred_label
int
&mac.mpo;_externalize_cred_label
&mac.externalize.paramdefs;
&mac.thead;
&mac.externalize.tbody;
&mac.externalize.para;
&mac.mpo;_externalize_ifnet_label
int
&mac.mpo;_externalize_ifnet_label
&mac.externalize.paramdefs;
&mac.thead;
&mac.externalize.tbody;
&mac.externalize.para;
&mac.mpo;_externalize_pipe_label
int
&mac.mpo;_externalize_pipe_label
&mac.externalize.paramdefs;
&mac.thead;
&mac.externalize.tbody;
&mac.externalize.para;
&mac.mpo;_externalize_socket_label
int
&mac.mpo;_externalize_socket_label
&mac.externalize.paramdefs;
&mac.thead;
&mac.externalize.tbody;
&mac.externalize.para;
&mac.mpo;_externalize_socket_peer_label
int
&mac.mpo;_externalize_socket_peer_label
&mac.externalize.paramdefs;
&mac.thead;
&mac.externalize.tbody;
&mac.externalize.para;
&mac.mpo;_externalize_vnode_label
int
&mac.mpo;_externalize_vnode_label
&mac.externalize.paramdefs;
&mac.thead;
&mac.externalize.tbody;
&mac.externalize.para;
&mac.mpo;_internalize_cred_label
int
&mac.mpo;_internalize_cred_label
&mac.internalize.paramdefs;
&mac.thead;
&mac.internalize.tbody;
&mac.internalize.para;
&mac.mpo;_internalize_ifnet_label
int
&mac.mpo;_internalize_ifnet_label
&mac.internalize.paramdefs;
&mac.thead;
&mac.internalize.tbody;
&mac.internalize.para;
&mac.mpo;_internalize_pipe_label
int
&mac.mpo;_internalize_pipe_label
&mac.internalize.paramdefs;
&mac.thead;
&mac.internalize.tbody;
&mac.internalize.para;
&mac.mpo;_internalize_socket_label
int
&mac.mpo;_internalize_socket_label
&mac.internalize.paramdefs;
&mac.thead;
&mac.internalize.tbody;
&mac.internalize.para;
&mac.mpo;_internalize_vnode_label
int
&mac.mpo;_internalize_vnode_label
&mac.internalize.paramdefs;
&mac.thead;
&mac.internalize.tbody;
&mac.internalize.para;
Label Events
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:
Label initialization o
(object-specific wait) \
Label creation o
\
Relabel events, o--<--.
Various object-specific, | |
Access control events ~-->--o
\
Label destruction o
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.
Label creation occurs when the kernel structure is
associated with an actual kernel object. For example, Mbufs
may be allocated and remain unused in a pool until they are
required. mbuf allocation causes label initialization on the
mbuf to take place, but mbuf creation occurs when the mbuf is
associated with a datagram. Typically, context will be
provided for a creation event, including the circumstances of
the creation, and labels of other relevant objects in the
creation process. For example, when an mbuf is created from a
socket, the socket and its label will be presented to
registered policies in addition to the new mbuf and its label.
Memory allocation in creation events is discouraged, as it may
occur in performance sensitive ports of the kernel; in
addition, creation calls are not permitted to fail so a
failure to allocate memory cannot be reported.
Object specific events do not generally fall into the
other broad classes of label events, but will generally
provide an opportunity to modify or update the label on an
object based on additional context. For example, the label on
an IP fragment reassembly queue may be updated during the
MAC_UPDATE_IPQ entry point as a result of the
acceptance of an additional mbuf to that queue.
Access control events are discussed in detail in the
following section.
Label destruction permits policies to release storage or
state associated with a label during its association with an
object so that the kernel data structures supporting the
object may be reused or released.
In addition to labels associated with specific kernel
objects, an additional class of labels exists: temporary
labels. These labels are used to store update information
submitted by user processes. These labels are initialized and
destroyed as with other label types, but the creation event is
MAC_INTERNALIZE, which accepts a user label
to be converted to an in-kernel representation.
File System Object Labeling Event Operations
&mac.mpo;_associate_vnode_devfs
void
&mac.mpo;_associate_vnode_devfs
struct mount
*mp
struct label
*fslabel
struct devfs_dirent
*de
struct label
*delabel
struct vnode
*vp
struct label
*vlabel
&mac.thead;
mp
Devfs mount point
fslabel
Devfs file system label
(mp->mnt_fslabel)
de
Devfs directory entry
delabel
Policy label associated with
de
vp
vnode associated with
de
vlabel
Policy label associated with
vp
Fill in the label (vlabel) for
a newly created devfs vnode based on the devfs directory
entry passed in de and its
label.
&mac.mpo;_associate_vnode_extattr
int
&mac.mpo;_associate_vnode_extattr
struct mount
*mp
struct label
*fslabel
struct vnode
*vp
struct label
*vlabel
&mac.thead;
mp
File system mount point
fslabel
File system label
vp
Vnode to label
vlabel
Policy label associated with
vp
Attempt to retrieve the label for
vp from the file system extended
attributes. Upon success, the value 0
is returned. Should extended attribute retrieval not be
supported, an accepted fallback is to copy
fslabel into
vlabel. In the event of an error,
an appropriate value for errno should
be returned.
&mac.mpo;_associate_vnode_singlelabel
void
&mac.mpo;_associate_vnode_singlelabel
struct mount
*mp
struct label
*fslabel
struct vnode
*vp
struct label
*vlabel
&mac.thead;
mp
File system mount point
fslabel
File system label
vp
Vnode to label
vlabel
Policy label associated with
vp
On non-multilabel file systems, this entry point is
called to set the policy label for
vp based on the file system label,
fslabel.
&mac.mpo;_create_devfs_device
void
&mac.mpo;_create_devfs_device
dev_t dev
struct devfs_dirent
*devfs_dirent
struct label
*label
&mac.thead;
dev
Device corresponding with
devfs_dirent
devfs_dirent
Devfs directory entry to be labeled.
label
Label for devfs_dirent
to be filled in.
Fill out the label on a devfs_dirent being created for
the passed device. This call will be made when the device
file system is mounted, regenerated, or a new device is made
available.
&mac.mpo;_create_devfs_directory
void
&mac.mpo;_create_devfs_directory
char *dirname
int dirnamelen
struct devfs_dirent
*devfs_dirent
struct label
*label
&mac.thead;
dirname
Name of directory being created
namelen
Length of string
dirname
devfs_dirent
Devfs directory entry for directory being
created.
Fill out the label on a devfs_dirent being created for
the passed directory. This call will be made when the device
file system is mounted, regenerated, or a new device
requiring a specific directory hierarchy is made
available.
&mac.mpo;_create_devfs_symlink
void
&mac.mpo;_create_devfs_symlink
struct ucred
*cred
struct mount
*mp
struct devfs_dirent
*dd
struct label
*ddlabel
struct devfs_dirent
*de
struct label
*delabel
&mac.thead;
cred
Subject credential
mp
Devfs mount point
dd
Link destination
ddlabel
Label associated with
dd
de
Symlink entry
delabel
Label associated with
de
Fill in the label (delabel) for
a newly created &man.devfs.5; symbolic link entry.
&mac.mpo;_create_vnode_extattr
int
&mac.mpo;_create_vnode_extattr
struct ucred
*cred
struct mount
*mp
struct label
*fslabel
struct vnode
*dvp
struct label
*dlabel
struct vnode
*vp
struct label
*vlabel
struct componentname
*cnp
&mac.thead;
cred
Subject credential
mount
File system mount point
label
File system label
dvp
Parent directory vnode
dlabel
Label associated with
dvp
vp
Newly created vnode
vlabel
Policy label associated with
vp
cnp
Component name for
vp
Write out the label for vp to
the appropriate extended attribute. If the write
succeeds, fill in vlabel with the
label, and return 0. Otherwise,
return an appropriate error.
&mac.mpo;_create_mount
void
&mac.mpo;_create_mount
struct ucred
*cred
struct mount
*mp
struct label
*mnt
struct label
*fslabel
&mac.thead;
cred
Subject credential
mp
Object; file system being mounted
mntlabel
Policy label to be filled in for
mp
fslabel
Policy label for the file system
mp mounts.
Fill out the labels on the mount point being created by
the passed subject credential. This call will be made when
a new file system is mounted.
&mac.mpo;_create_root_mount
void
&mac.mpo;_create_root_mount
struct ucred
*cred
struct mount
*mp
struct label
*mntlabel
struct label
*fslabel
&mac.thead;
See .
Fill out the labels on the mount point being created by
the passed subject credential. This call will be made when
the root file system is mounted, after
&mac.mpo;_create_mount;.
&mac.mpo;_relabel_vnode
void
&mac.mpo;_relabel_vnode
struct ucred
*cred
struct vnode
*vp
struct label
*vnodelabel
struct label
*newlabel
&mac.thead;
cred
Subject credential
vp
vnode to relabel
vnodelabel
Existing policy label for
vp
newlabel
New, possibly partial label to replace
vnodelabel
Update the label on the passed vnode given the passed
update vnode label and the passed subject credential.
&mac.mpo;_setlabel_vnode_extattr
int
&mac.mpo;_setlabel_vnode_extattr
struct ucred
*cred
struct vnode
*vp
struct label
*vlabel
struct label
*intlabel
&mac.thead;
cred
Subject credential
vp
Vnode for which the label is being
written
vlabel
Policy label associated with
vp
intlabel
Label to write out
Write out the policy from
intlabel to an extended
attribute. This is called from
vop_stdcreatevnode_ea.
&mac.mpo;_update_devfsdirent
void
&mac.mpo;_update_devfsdirent
struct devfs_dirent
*devfs_dirent
struct label
*direntlabel
struct vnode
*vp
struct label
*vnodelabel
&mac.thead;
devfs_dirent
Object; devfs directory entry
direntlabel
Policy label for
devfs_dirent to be
updated.
vp
Parent vnode
Locked
vnodelabel
Policy label for
vp
Update the devfs_dirent label
from the passed devfs vnode label. This call will be made
when a devfs vnode has been successfully relabeled to commit
the label change such that it lasts even if the vnode is
recycled. It will also be made when when a symlink is
created in devfs, following a call to
mac_vnode_create_from_vnode to
initialize the vnode label.
IPC Object Labeling Event Operations
&mac.mpo;_create_mbuf_from_socket
void
&mac.mpo;_create_mbuf_from_socket
struct socket
*so
struct label
*socketlabel
struct mbuf *m
struct label
*mbuflabel
&mac.thead;
socket
Socket
Socket locking WIP
socketlabel
Policy label for
socket
m
Object; mbuf
mbuflabel
Policy label to fill in for
m
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.
&mac.mpo;_create_pipe
void
&mac.mpo;_create_pipe
struct ucred
*cred
struct pipe
*pipe
struct label
*pipelabel
&mac.thead;
cred
Subject credential
pipe
Pipe
pipelabel
Policy label associated with
pipe
Set the label on a newly created pipe from the passed
subject credential. This call is made when a new pipe is
created.
&mac.mpo;_create_socket
void
&mac.mpo;_create_socket
struct ucred
*cred
struct socket
*so
struct label
*socketlabel
&mac.thead;
cred
Subject credential
Immutable
so
Object; socket to label
socketlabel
Label to fill in for
so
Set the label on a newly created socket from the passed
subject credential. This call is made when a socket is
created.
&mac.mpo;_create_socket_from_socket
void
&mac.mpo;_create_socket_from_socket
struct socket
*oldsocket
struct label
*oldsocketlabel
struct socket
*newsocket
struct label
*newsocketlabel
&mac.thead;
oldsocket
Listening socket
oldsocketlabel
Policy label associated with
oldsocket
newsocket
New socket
newsocketlabel
Policy label associated with
newsocketlabel
Label a socket, newsocket,
newly &man.accept.2;ed, based on the &man.listen.2;
socket, oldsocket.
&mac.mpo;_relabel_pipe
void
&mac.mpo;_relabel_pipe
struct ucred
*cred
struct pipe
*pipe
struct label
*oldlabel
struct label
*newlabel
&mac.thead;
cred
Subject credential
pipe
Pipe
oldlabel
Current policy label associated with
pipe
newlabel
Policy label update to apply to
pipe
Apply a new label, newlabel, to
pipe.
&mac.mpo;_relabel_socket
void
&mac.mpo;_relabel_socket
struct ucred
*cred
struct socket
*so
struct label
*oldlabel
struct label
*newlabel
&mac.thead;
cred
Subject credential
Immutable
so
Object; socket
oldlabel
Current label for
so
newlabel
Label update for
so
Update the label on a socket from the passed socket
label update.
&mac.mpo;_set_socket_peer_from_mbuf
void
&mac.mpo;_set_socket_peer_from_mbuf
struct mbuf
*mbuf
struct label
*mbuflabel
struct label
*oldlabel
struct label
*newlabel
&mac.thead;
mbuf
First datagram received over socket
mbuflabel
Label for mbuf
oldlabel
Current label for the socket
newlabel
Policy label to be filled out for the
socket
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.
&mac.mpo;_set_socket_peer_from_socket
void
&mac.mpo;_set_socket_peer_from_socket
struct socket
*oldsocket
struct label
*oldsocketlabel
struct socket
*newsocket
struct label
*newsocketpeerlabel
&mac.thead;
oldsocket
Local socket
oldsocketlabel
Policy label for
oldsocket
newsocket
Peer socket
newsocketpeerlabel
Policy label to fill in for
newsocket
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.
Network Object Labeling Event Operations
&mac.mpo;_create_bpfdesc
void
&mac.mpo;_create_bpfdesc
struct ucred
*cred
struct bpf_d
*bpf_d
struct label
*bpflabel
&mac.thead;
cred
Subject credential
Immutable
bpf_d
Object; bpf descriptor
bpf
Policy label to be filled in for
bpf_d
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.
&mac.mpo;_create_ifnet
void
&mac.mpo;_create_ifnet
struct ifnet
*ifnet
struct label
*ifnetlabel
&mac.thead;
ifnet
Network interface
ifnetlabel
Policy label to fill in for
ifnet
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.
&mac.mpo;_create_ipq
void
&mac.mpo;_create_ipq
struct mbuf
*fragment
struct label
*fragmentlabel
struct ipq
*ipq
struct label
*ipqlabel
&mac.thead;
fragment
First received IP fragment
fragmentlabel
Policy label for
fragment
ipq
IP reassembly queue to be labeled
ipqlabel
Policy label to be filled in for
ipq
Set the label on a newly created IP fragment reassembly
queue from the mbuf header of the first received
fragment.
&mac.mpo;_create_datagram_from_ipq
void
&mac.mpo;_create_create_datagram_from_ipq
struct ipq
*ipq
struct label
*ipqlabel
struct mbuf
*datagram
struct label
*datagramlabel
&mac.thead;
ipq
IP reassembly queue
ipqlabel
Policy label for
ipq
datagram
Datagram to be labeled
datagramlabel
Policy label to be filled in for
datagramlabel
Set the label on a newly reassembled IP datagram from
the IP fragment reassembly queue from which it was
generated.
&mac.mpo;_create_fragment
void
&mac.mpo;_create_fragment
struct mbuf
*datagram
struct label
*datagramlabel
struct mbuf
*fragment
struct label
*fragmentlabel
&mac.thead;
datagram
Datagram
datagramlabel
Policy label for
datagram
fragment
Fragment to be labeled
fragmentlabel
Policy label to be filled in for
datagram
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.
&mac.mpo;_create_mbuf_from_mbuf
void
&mac.mpo;_create_mbuf_from_mbuf
struct mbuf
*oldmbuf
struct label
*oldmbuflabel
struct mbuf
*newmbuf
struct label
*newmbuflabel
&mac.thead;
oldmbuf
Existing (source) mbuf
oldmbuflabel
Policy label for
oldmbuf
newmbuf
New mbuf to be labeled
newmbuflabel
Policy label to be filled in for
newmbuf
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.
&mac.mpo;_create_mbuf_linklayer
void
&mac.mpo;_create_mbuf_linklayer
struct ifnet
*ifnet
struct label
*ifnetlabel
struct mbuf
*mbuf
struct label
*mbuflabel
&mac.thead;
ifnet
Network interface
ifnetlabel
Policy label for
ifnet
mbuf
mbuf header for new datagram
mbuflabel
Policy label to be filled in for
mbuf
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.
&mac.mpo;_create_mbuf_from_bpfdesc
void
&mac.mpo;_create_mbuf_from_bpfdesc
struct bpf_d
*bpf_d
struct label
*bpflabel
struct mbuf
*mbuf
struct label
*mbuflabel
&mac.thead;
bpf_d
BPF descriptor
bpflabel
Policy label for
bpflabel
mbuf
New mbuf to be labeled
mbuflabel
Policy label to fill in for
mbuf
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.
&mac.mpo;_create_mbuf_from_ifnet
void
&mac.mpo;_create_mbuf_from_ifnet
struct ifnet
*ifnet
struct label
*ifnetlabel
struct mbuf
*mbuf
struct label
*mbuflabel
&mac.thead;
ifnet
Network interface
ifnetlabel
Policy label for
ifnetlabel
mbuf
mbuf header for new datagram
mbuflabel
Policy label to be filled in for
mbuf
Set the label on the mbuf header of a newly created
datagram generated from the passed network interface.
&mac.mpo;_create_mbuf_multicast_encap
void
&mac.mpo;_create_mbuf_multicast_encap
struct mbuf
*oldmbuf
struct label
*oldmbuflabel
struct ifnet
*ifnet
struct label
*ifnetlabel
struct mbuf
*newmbuf
struct label
*newmbuflabel
&mac.thead;
oldmbuf
mbuf header for existing datagram
oldmbuflabel
Policy label for
oldmbuf
ifnet
Network interface
ifnetlabel
Policy label for
ifnet
newmbuf
mbuf header to be labeled for new
datagram
newmbuflabel
Policy label to be filled in for
newmbuf
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.
&mac.mpo;_create_mbuf_netlayer
void
&mac.mpo;_create_mbuf_netlayer
struct mbuf
*oldmbuf
struct label
*oldmbuflabel
struct mbuf
*newmbuf
struct label
*newmbuflabel
&mac.thead;
oldmbuf
Received datagram
oldmbuflabel
Policy label for
oldmbuf
newmbuf
Newly created datagram
newmbuflabel
Policy label for
newmbuf
Set the label on the mbuf header of a newly created
datagram generated by the IP stack in response to an
existing received datagram (oldmbuf).
This call may be made in a number of situations, including
when responding to ICMP request datagrams.
&mac.mpo;_fragment_match
int
&mac.mpo;_fragment_match
struct mbuf
*fragment
struct label
*fragmentlabel
struct ipq
*ipq
struct label
*ipqlabel
&mac.thead;
fragment
IP datagram fragment
fragmentlabel
Policy label for
fragment
ipq
IP fragment reassembly queue
ipqlabel
Policy label for
ipq
Determine whether an mbuf header containing an IP
datagram (fragment) fragment matches
the label of the passed IP fragment reassembly queue
(ipq). Return
(1) for a successful match, or
(0) for no match. This call is
made when the IP stack attempts to find an existing fragment
reassembly queue for a newly received fragment; if this
fails, a new fragment reassembly queue may be instantiated
for the fragment. Policies may use this entry point to
prevent the reassembly of otherwise matching IP fragments if
policy does not permit them to be reassembled based on the
label or other information.
&mac.mpo;_relabel_ifnet
void
&mac.mpo;_relabel_ifnet
struct ucred
*cred
struct ifnet
*ifnet
struct label
*ifnetlabel
struct label
*newlabel
&mac.thead;
cred
Subject credential
ifnet
Object; Network interface
ifnetlabel
Policy label for
ifnet
newlabel
Label update to apply to
ifnet
Update the label of network interface,
ifnet, based on the passed update
label, newlabel, and the passed
subject credential, cred.
&mac.mpo;_update_ipq
void
&mac.mpo;_update_ipq
struct mbuf
*fragment
struct label
*fragmentlabel
struct ipq
*ipq
struct label
*ipqlabel
&mac.thead;
mbuf
IP fragment
mbuflabel
Policy label for
mbuf
ipq
IP fragment reassembly queue
ipqlabel
Policy label to be updated for
ipq
Update the label on an IP fragment reassembly queue
(ipq) based on the acceptance of the
passed IP fragment mbuf header
(mbuf).
Process Labeling Event Operations
&mac.mpo;_create_cred
void
&mac.mpo;_create_cred
struct ucred
*parent_cred
struct ucred
*child_cred
&mac.thead;
parent_cred
Parent subject credential
child_cred
Child subject credential
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 struct
ucred. This call should not be confused with a
process forking or creation event.
&mac.mpo;_execve_transition
void
&mac.mpo;_execve_transition
struct ucred
*old
struct ucred
*new
struct vnode
*vp
struct label
*vnodelabel
&mac.thead;
old
Existing subject credential
Immutable
new
New subject credential to be labeled
vp
File to execute
Locked
vnodelabel
Policy label for
vp
Update the label of a newly created subject credential
(new) from the passed existing
subject credential (old) based on a
label transition caused by executing the passed vnode
(vp). This call occurs when a
process executes the passed vnode and one of the policies
returns a success from the
mpo_execve_will_transition entry point.
Policies may choose to implement this call simply by
invoking mpo_create_cred and passing
the two subject credentials so as not to implement a
transitioning event. Policies should not leave this entry
point unimplemented if they implement
mpo_create_cred, even if they do not
implement
mpo_execve_will_transition.
&mac.mpo;_execve_will_transition
int
&mac.mpo;_execve_will_transition
struct ucred
*old
struct vnode
*vp
struct label
*vnodelabel
&mac.thead;
old
Subject credential prior to
&man.execve.2;
Immutable
vp
File to execute
vnodelabel
Policy label for
vp
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
1 if a transition is required,
0 if not. Even if a policy
returns 0, it should behave
correctly in the presence of an unexpected invocation of
mpo_execve_transition, as that call may
happen as a result of another policy requesting a
transition.
&mac.mpo;_create_proc0
void
&mac.mpo;_create_proc0
struct ucred
*cred
&mac.thead;
cred
Subject credential to be filled in
Create the subject credential of process 0, the parent
of all kernel processes.
&mac.mpo;_create_proc1
void
&mac.mpo;_create_proc1
struct ucred
*cred
&mac.thead;
cred
Subject credential to be filled in
Create the subject credential of process 1, the parent
of all user processes.
&mac.mpo;_relabel_cred
void
&mac.mpo;_relabel_cred
struct ucred
*cred
struct label
*newlabel
&mac.thead;
cred
Subject credential
newlabel
Label update to apply to
cred
Update the label on a subject credential from the passed
update label.
Access Control Checks
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
error_select() function in
kern_mac.c:
Most precedence
EDEADLK
EINVAL
ESRCH
EACCES
Least precedence
EPERM
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.
&mac.mpo;_check_bpfdesc_receive
int
&mac.mpo;_check_bpfdesc_receive
struct bpf_d
*bpf_d
struct label
*bpflabel
struct ifnet
*ifnet
struct label
*ifnetlabel
&mac.thead;
bpf_d
Subject; BPF descriptor
bpflabel
Policy label for
bpf_d
ifnet
Object; network interface
ifnetlabel
Policy label for
ifnet
Determine whether the MAC framework should permit
datagrams from the passed interface to be delivered to the
buffers of the passed BPF descriptor. Return
(0) for success, or an
errno value for failure Suggested
failure: EACCES for label mismatches,
EPERM for lack of privilege.
&mac.mpo;_check_kenv_dump
int
&mac.mpo;_check_kenv_dump
struct ucred
*cred
&mac.thead;
cred
Subject credential
Determine whether the subject should be allowed to
retrieve the kernel environment (see &man.kenv.2;).
&mac.mpo;_check_kenv_get
int
&mac.mpo;_check_kenv_get
struct ucred
*cred
char *name
&mac.thead;
cred
Subject credential
name
Kernel environment variable name
Determine whether the subject should be allowed to
retrieve the value of the specified kernel environment
variable.
&mac.mpo;_check_kenv_set
int
&mac.mpo;_check_kenv_set
struct ucred
*cred
char *name
&mac.thead;
cred
Subject credential
name
Kernel environment variable name
Determine whether the subject should be allowed to set
the specified kernel environment variable.
&mac.mpo;_check_kenv_unset
int
&mac.mpo;_check_kenv_unset
struct ucred
*cred
char *name
&mac.thead;
cred
Subject credential
name
Kernel environment variable name
Determine whether the subject should be allowed to unset
the specified kernel environment variable.
&mac.mpo;_check_kld_load
int
&mac.mpo;_check_kld_load
struct ucred
*cred
struct vnode
*vp
struct label
*vlabel
&mac.thead;
cred
Subject credential
vp
Kernel module vnode
vlabel
Label associated with
vp
Determine whether the subject should be allowed to load
the specified module file.
&mac.mpo;_check_kld_stat
int
&mac.mpo;_check_kld_stat
struct ucred
*cred
&mac.thead;
cred
Subject credential
Determine whether the subject should be allowed to
retrieve a list of loaded kernel module files and associated
statistics.
&mac.mpo;_check_kld_unload
int
&mac.mpo;_check_kld_unload
struct ucred
*cred
&mac.thead;
cred
Subject credential
Determine whether the subject should be allowed to
unload a kernel module.
&mac.mpo;_check_pipe_ioctl
int
&mac.mpo;_check_pipe_ioctl
struct ucred
*cred
struct pipe
*pipe
struct label
*pipelabel
unsigned long
cmd
void *data
&mac.thead;
cred
Subject credential
pipe
Pipe
pipelabel
Policy label associated with
pipe
cmd
&man.ioctl.2; command
data
&man.ioctl.2; data
Determine whether the subject should be allowed to make
the specified &man.ioctl.2; call.
&mac.mpo;_check_pipe_poll
int
&mac.mpo;_check_pipe_poll
struct ucred
*cred
struct pipe
*pipe
struct label
*pipelabel
&mac.thead;
cred
Subject credential
pipe
Pipe
pipelabel
Policy label associated with
pipe
Determine whether the subject should be allowed to poll
pipe.
&mac.mpo;_check_pipe_read
int
&mac.mpo;_check_pipe_read
struct ucred
*cred
struct pipe
*pipe
struct label
*pipelabel
&mac.thead;
cred
Subject credential
pipe
Pipe
pipelabel
Policy label associated with
pipe
Determine whether the subject should be allowed read
access to pipe.
&mac.mpo;_check_pipe_relabel
int
&mac.mpo;_check_pipe_relabel
struct ucred
*cred
struct pipe
*pipe
struct label
*pipelabel
struct label
*newlabel
&mac.thead;
cred
Subject credential
pipe
Pipe
pipelabel
Current policy label associated with
pipe
newlabel
Label update to
pipelabel
Determine whether the subject should be allowed to
relabel pipe.
&mac.mpo;_check_pipe_stat
int
&mac.mpo;_check_pipe_stat
struct ucred
*cred
struct pipe
*pipe
struct label
*pipelabel
&mac.thead;
cred
Subject credential
pipe
Pipe
pipelabel
Policy label associated with
pipe
Determine whether the subject should be allowed to
retrieve statistics related to
pipe.
&mac.mpo;_check_pipe_write
int
&mac.mpo;_check_pipe_write
struct ucred
*cred
struct pipe
*pipe
struct label
*pipelabel
&mac.thead;
cred
Subject credential
pipe
Pipe
pipelabel
Policy label associated with
pipe
Determine whether the subject should be allowed to write
to pipe.
&mac.mpo;_check_socket_bind
int
&mac.mpo;_check_socket_bind
struct ucred
*cred
struct socket
*socket
struct label
*socketlabel
struct sockaddr
*sockaddr
&mac.thead;
cred
Subject credential
socket
Socket to be bound
socketlabel
Policy label for
socket
sockaddr
Address of
socket
&mac.mpo;_check_socket_connect
int
&mac.mpo;_check_socket_connect
struct ucred
*cred
struct socket
*socket
struct label
*socketlabel
struct sockaddr
*sockaddr
&mac.thead;
cred
Subject credential
socket
Socket to be connected
socketlabel
Policy label for
socket
sockaddr
Address of
socket
Determine whether the subject credential
(cred) can connect the passed socket
(socket) to the passed socket address
(sockaddr). Return
0 for success, or an
errno value for failure. Suggested
failure: EACCES for label mismatches,
EPERM for lack of privilege.
&mac.mpo;_check_socket_receive
int
&mac.mpo;_check_socket_receive
struct ucred
*cred
struct socket
*so
struct label
*socketlabel
&mac.thead;
cred
Subject credential
so
Socket
socketlabel
Policy label associated with
so
Determine whether the subject should be allowed to
receive information from the socket
so.
&mac.mpo;_check_socket_send
int
&mac.mpo;_check_socket_send
struct ucred
*cred
struct socket
*so
struct label
*socketlabel
&mac.thead;
cred
Subject credential
so
Socket
socketlabel
Policy label associated with
so
Determine whether the subject should be allowed to send
information across the socket
so.
&mac.mpo;_check_cred_visible
int
&mac.mpo;_check_cred_visible
struct ucred
*u1
struct ucred
*u2
&mac.thead;
u1
Subject credential
u2
Object credential
Determine whether the subject credential
u1 can see
other
subjects with the passed subject credential
u2. Return
0 for success, or an
errno value for failure. Suggested
failure: EACCES for label mismatches,
EPERM for lack of privilege, or
ESRCH to hide visibility. This call
may be made in a number of situations, including
inter-process status sysctl's used by ps,
and in procfs lookups.
&mac.mpo;_check_socket_visible
int
&mac.mpo;_check_socket_visible
struct ucred
*cred
struct socket
*socket
struct label
*socketlabel
&mac.thead;
cred
Subject credential
socket
Object; socket
socketlabel
Policy label for
socket
&mac.mpo;_check_ifnet_relabel
int
&mac.mpo;_check_ifnet_relabel
struct ucred
*cred
struct ifnet
*ifnet
struct label
*ifnetlabel
struct label
*newlabel
&mac.thead;
cred
Subject credential
ifnet
Object; network interface
ifnetlabel
Existing policy label for
ifnet
newlabel
Policy label update to later be applied to
ifnet
Determine whether the subject credential can relabel the
passed network interface to the passed label update.
&mac.mpo;_check_socket_relabel
int
&mac.mpo;_check_socket_relabel
struct ucred
*cred
struct socket
*socket
struct label
*socketlabel
struct label
*newlabel
&mac.thead;
cred
Subject credential
socket
Object; socket
socketlabel
Existing policy label for
socket
newlabel
Label update to later be applied to
socketlabel
Determine whether the subject credential can relabel the
passed socket to the passed label update.
&mac.mpo;_check_cred_relabel
int
&mac.mpo;_check_cred_relabel
struct ucred
*cred
struct label
*newlabel
&mac.thead;
cred
Subject credential
newlabel
Label update to later be applied to
cred
Determine whether the subject credential can relabel
itself to the passed label update.
&mac.mpo;_check_vnode_relabel
int
&mac.mpo;_check_vnode_relabel
struct ucred
*cred
struct vnode
*vp
struct label
*vnodelabel
struct label
*newlabel
&mac.thead;
cred
Subject credential
Immutable
vp
Object; vnode
Locked
vnodelabel
Existing policy label for
vp
newlabel
Policy label update to later be applied to
vp
Determine whether the subject credential can relabel the
passed vnode to the passed label update.
&mac.mpo;_check_mount_stat
int &mac.mpo;_check_mount_stat
struct ucred
*cred
struct mount
*mp
struct label
*mountlabel
&mac.thead;
cred
Subject credential
mp
Object; file system mount
mountlabel
Policy label for
mp
Determine whether the subject credential can see the
results of a statfs performed on the file system. Return
0 for success, or an
errno value for failure. Suggested
failure: EACCES for label mismatches
or EPERM for lack of privilege. This
call may be made in a number of situations, including during
invocations of &man.statfs.2; and related calls, as well as to
determine what file systems to exclude from listings of file
systems, such as when &man.getfsstat.2; is invoked.
&mac.mpo;_check_proc_debug
int
&mac.mpo;_check_proc_debug
struct ucred
*cred
struct proc
*proc
&mac.thead;
cred
Subject credential
Immutable
proc
Object; process
Determine whether the subject credential can debug the
passed process. Return 0 for
success, or an errno value for failure.
Suggested failure: EACCES for label
mismatch, EPERM for lack of
privilege, or ESRCH to hide
visibility of the target. This call may be made in a number
of situations, including use of the &man.ptrace.2; and
&man.ktrace.2; APIs, as well as for some types of procfs
operations.
&mac.mpo;_check_vnode_access
int
&mac.mpo;_check_vnode_access
struct ucred
*cred
struct vnode
*vp
struct label
*label
int flags
&mac.thead;
cred
Subject credential
vp
Object; vnode
label
Policy label for
vp
flags
&man.access.2; flags
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 &mac.mpo;_check_vnode_open.
Return 0 for success, or an
errno value for failure. Suggested
failure: EACCES for label mismatches
or EPERM for lack of
privilege.
&mac.mpo;_check_vnode_chdir
int
&mac.mpo;_check_vnode_chdir
struct ucred
*cred
struct vnode
*dvp
struct label
*dlabel
&mac.thead;
cred
Subject credential
dvp
Object; vnode to &man.chdir.2; into
dlabel
Policy label for
dvp
Determine whether the subject credential can change the
process working directory to the passed vnode. Return
0 for success, or an
errno value for failure. Suggested
failure: EACCES for label mismatch,
or EPERM for lack of
privilege.
&mac.mpo;_check_vnode_chroot
int
&mac.mpo;_check_vnode_chroot
struct ucred
*cred
struct vnode
*dvp
struct label
*dlabel
&mac.thead;
cred
Subject credential
dvp
Directory vnode
dlabel
Policy label associated with
dvp
Determine whether the subject should be allowed to
&man.chroot.2; into the specified directory
(dvp).
&mac.mpo;_check_vnode_create
int
&mac.mpo;_check_vnode_create
struct ucred
*cred
struct vnode
*dvp
struct label
*dlabel
struct componentname
*cnp
struct vattr
*vap
&mac.thead;
cred
Subject credential
dvp
Object; vnode
dlabel
Policy label for
dvp
cnp
Component name for
dvp
vap
vnode attributes for vap
Determine whether the subject credential can create a
vnode with the passed parent directory, passed name
information, and passed attribute information. Return
0 for success, or an
errno value for failure. Suggested
failure: EACCES for label mismatch,
or EPERM for lack of privilege.
This call may be made in a number of situations, including
as a result of calls to &man.open.2; with
O_CREAT, &man.mknod.2;, &man.mkfifo.2;, and
others.
&mac.mpo;_check_vnode_delete
int
&mac.mpo;_check_vnode_delete
struct ucred
*cred
struct vnode
*dvp
struct label
*dlabel
struct vnode
*vp
void *label
struct componentname
*cnp
&mac.thead;
cred
Subject credential
dvp
Parent directory vnode
dlabel
Policy label for
dvp
vp
Object; vnode to delete
label
Policy label for
vp
cnp
Component name for
vp
Determine whether the subject credential can delete a
vnode from the passed parent directory and passed name
information. Return 0 for
success, or an errno value for failure.
Suggested failure: EACCES for label
mismatch, or EPERM for lack of
privilege. This call may be made in a number of situations,
including as a result of calls to &man.unlink.2; and
&man.rmdir.2;. Policies implementing this entry point
should also implement
mpo_check_rename_to to authorize
deletion of objects as a result of being the target of a
rename.
&mac.mpo;_check_vnode_deleteacl
int
&mac.mpo;_check_vnode_deleteacl
struct ucred *cred
struct vnode *vp
struct label *label
acl_type_t type
&mac.thead;
cred
Subject credential
Immutable
vp
Object; vnode
Locked
label
Policy label for
vp
type
ACL type
Determine whether the subject credential can delete the
ACL of passed type from the passed vnode. Return
0 for success, or an
errno value for failure. Suggested
failure: EACCES for label mismatch,
or EPERM for lack of
privilege.
&mac.mpo;_check_vnode_exec
int
&mac.mpo;_check_vnode_exec
struct ucred
*cred
struct vnode
*vp
struct label
*label
&mac.thead;
cred
Subject credential
vp
Object; vnode to execute
label
Policy label for
vp
Determine whether the subject credential can execute the
passed vnode. Determination of execute privilege is made
separately from decisions about any transitioning event.
Return 0 for success, or an
errno value for failure. Suggested
failure: EACCES for label mismatch,
or EPERM for lack of
privilege.
&mac.mpo;_check_vnode_getacl
int
&mac.mpo;_check_vnode_getacl
struct ucred
*cred
struct vnode
*vp
struct label
*label
acl_type_t
type
&mac.thead;
cred
Subject credential
vp
Object; vnode
label
Policy label for
vp
type
ACL type
Determine whether the subject credential can retrieve
the ACL of passed type from the passed vnode. Return
0 for success, or an
errno value for failure. Suggested
failure: EACCES for label mismatch,
or EPERM for lack of
privilege.
&mac.mpo;_check_vnode_getextattr
int
&mac.mpo;_check_vnode_getextattr
struct ucred
*cred
struct vnode
*vp
struct label
*label
int
attrnamespace
const char
*name
struct uio
*uio
&mac.thead;
cred
Subject credential
vp
Object; vnode
label
Policy label for
vp
attrnamespace
Extended attribute namespace
name
Extended attribute name
uio
I/O structure pointer; see &man.uio.9;
Determine whether the subject credential can retrieve
the extended attribute with the passed namespace and name
from the passed vnode. Policies implementing labeling using
extended attributes may be interested in special handling of
operations on those extended attributes. Return
0 for success, or an
errno value for failure. Suggested
failure: EACCES for label mismatch,
or EPERM for lack of
privilege.
&mac.mpo;_check_vnode_link
int
&mac.mpo;_check_vnode_link
struct ucred
*cred
struct vnode
*dvp
struct label
*dlabel
struct vnode
*vp
struct label
*label
struct componentname
*cnp
&mac.thead;
cred
Subject credential
dvp
Directory vnode
dlabel
Policy label associated with
dvp
vp
Link destination vnode
label
Policy label associated with
vp
cnp
Component name for the link being created
Determine whether the subject should be allowed to
create a link to the vnode vp with
the name specified by cnp.
&mac.mpo;_check_vnode_mmap
int
&mac.mpo;_check_vnode_mmap
struct ucred
*cred
struct vnode
*vp
struct label
*label
int prot
&mac.thead;
cred
Subject credential
vp
Vnode to map
label
Policy label associated with
vp
prot
Mmap protections (see &man.mmap.2;)
Determine whether the subject should be allowed to map
the vnode vp with the protections
specified in prot.
&mac.mpo;_check_vnode_mmap_downgrade
void
&mac.mpo;_check_vnode_mmap_downgrade
struct ucred
*cred
struct vnode
*vp
struct label
*label
int *prot
&mac.thead;
cred
See
.
vp
label
prot
Mmap protections to be downgraded
Downgrade the mmap protections based on the subject and
object labels.
&mac.mpo;_check_vnode_mprotect
int
&mac.mpo;_check_vnode_mprotect
struct ucred
*cred
struct vnode
*vp
struct label
*label
int prot
&mac.thead;
cred
Subject credential
vp
Mapped vnode
prot
Memory protections
Determine whether the subject should be allowed to
set the specified memory protections on memory mapped from
the vnode vp.
&mac.mpo;_check_vnode_poll
int
&mac.mpo;_check_vnode_poll
struct ucred
*active_cred
struct ucred
*file_cred
struct vnode
*vp
struct label
*label
&mac.thead;
active_cred
Subject credential
file_cred
Credential associated with the struct
file
vp
Polled vnode
label
Policy label associated with
vp
Determine whether the subject should be allowed to poll
the vnode vp.
&mac.mpo;_check_vnode_rename_from
int
&mac.mpo;_vnode_rename_from
struct ucred
*cred
struct vnode
*dvp
struct label
*dlabel
struct vnode
*vp
struct label
*label
struct componentname
*cnp
&mac.thead;
cred
Subject credential
dvp
Directory vnode
dlabel
Policy label associated with
dvp
vp
Vnode to be renamed
label
Policy label associated with
vp
cnp
Component name for
vp
Determine whether the subject should be allowed to
rename the vnode vp to something
else.
&mac.mpo;_check_vnode_rename_to
int
&mac.mpo;_check_vnode_rename_to
struct ucred
*cred
struct vnode
*dvp
struct label
*dlabel
struct vnode
*vp
struct label
*label
int samedir
struct componentname
*cnp
&mac.thead;
cred
Subject credential
dvp
Directory vnode
dlabel
Policy label associated with
dvp
vp
Overwritten vnode
label
Policy label associated with
vp
samedir
Boolean; 1 if the source and
destination directories are the same
cnp
Destination component name
Determine whether the subject should be allowed to
rename to the vnode vp, into the
directory dvp, or to the name
represented by cnp. If there is no
existing file to overwrite, vp and
label will be NULL.
&mac.mpo;_check_socket_listen
int
&mac.mpo;_check_socket_listen
struct ucred
*cred
struct socket
*socket
struct label
*socketlabel
&mac.thead;
cred
Subject credential
socket
Object; socket
socketlabel
Policy label for
socket
Determine whether the subject credential can listen on
the passed socket. Return 0 for
success, or an errno value for failure.
Suggested failure: EACCES for label
mismatch, or EPERM for lack of
privilege.
&mac.mpo;_check_vnode_lookup
int
&mac.mpo;_check_vnode_lookup
struct ucred
*cred
struct vnode
*dvp
struct label
*dlabel
struct componentname
*cnp
&mac.thead;
cred
Subject credential
dvp
Object; vnode
dlabel
Policy label for
dvp
cnp
Component name being looked up
Determine whether the subject credential can perform a
lookup in the passed directory vnode for the passed name.
Return 0 for success, or an
errno value for failure. Suggested
failure: EACCES for label mismatch,
or EPERM for lack of
privilege.
&mac.mpo;_check_vnode_open
int
&mac.mpo;_check_vnode_open
struct ucred
*cred
struct vnode
*vp
struct label
*label
int
acc_mode
&mac.thead;
cred
Subject credential
vp
Object; vnode
label
Policy label for
vp
acc_mode
&man.open.2; access mode
Determine whether the subject credential can perform an
open operation on the passed vnode with the passed access
mode. Return 0 for success, or
an errno value for failure. Suggested failure:
EACCES for label mismatch, or
EPERM for lack of privilege.
&mac.mpo;_check_vnode_readdir
int
&mac.mpo;_check_vnode_readdir
struct ucred
*cred
struct vnode
*dvp
struct label
*dlabel
&mac.thead;
cred
Subject credential
dvp
Object; directory vnode
dlabel
Policy label for
dvp
Determine whether the subject credential can perform a
readdir operation on the passed
directory vnode. Return 0 for
success, or an errno value for failure.
Suggested failure: EACCES for label
mismatch, or EPERM for lack of
privilege.
&mac.mpo;_check_vnode_readlink
int
&mac.mpo;_check_vnode_readlink
struct ucred
*cred
struct vnode
*vp
struct label
*label
&mac.thead;
cred
Subject credential
vp
Object; vnode
label
Policy label for
vp
Determine whether the subject credential can perform a
readlink operation on the passed
symlink vnode. Return 0 for
success, or an errno value for failure.
Suggested failure: EACCES for label
mismatch, or EPERM for lack of
privilege. This call may be made in a number of situations,
including an explicit readlink call by
the user process, or as a result of an implicit
readlink during a name lookup by the
process.
&mac.mpo;_check_vnode_revoke
int
&mac.mpo;_check_vnode_revoke
struct ucred
*cred
struct vnode
*vp
struct label
*label
&mac.thead;
cred
Subject credential
vp
Object; vnode
label
Policy label for
vp
Determine whether the subject credential can revoke
access to the passed vnode. Return
0 for success, or an
errno value for failure. Suggested
failure: EACCES for label mismatch,
or EPERM for lack of
privilege.
&mac.mpo;_check_vnode_setacl
int
&mac.mpo;_check_vnode_setacl
struct ucred
*cred
struct vnode
*vp
struct label
*label
acl_type_t
type
struct acl
*acl
&mac.thead;
cred
Subject credential
vp
Object; vnode
label
Policy label for
vp
type
ACL type
acl
ACL
Determine whether the subject credential can set the
passed ACL of passed type on the passed vnode. Return
0 for success, or an
errno value for failure. Suggested
failure: EACCES for label mismatch,
or EPERM for lack of
privilege.
&mac.mpo;_check_vnode_setextattr
int
&mac.mpo;_check_vnode_setextattr
struct ucred
*cred
struct vnode
*vp
struct label
*label
int
attrnamespace
const char
*name
struct uio
*uio
&mac.thead;
cred
Subject credential
vp
Object; vnode
label
Policy label for vp
attrnamespace
Extended attribute namespace
name
Extended attribute name
uio
I/O structure pointer; see &man.uio.9;
Determine whether the subject credential can set the
extended attribute of passed name and passed namespace on
the passed vnode. Policies implementing security labels
backed into extended attributes may want to provide
additional protections for those attributes. Additionally,
policies should avoid making decisions based on the data
referenced from uio, as there is a
potential race condition between this check and the actual
operation. The uio may also be
NULL if a delete operation is being
performed. Return 0 for success,
or an errno value for failure. Suggested
failure: EACCES for label mismatch,
or EPERM for lack of
privilege.
&mac.mpo;_check_vnode_setflags
int
&mac.mpo;_check_vnode_setflags
struct ucred
*cred
struct vnode
*vp
struct label
*label
u_long flags
&mac.thead;
cred
Subject credential
vp
Object; vnode
label
Policy label for
vp
flags
File flags; see &man.chflags.2;
Determine whether the subject credential can set the
passed flags on the passed vnode. Return
0 for success, or an
errno value for failure. Suggested
failure: EACCES for label mismatch,
or EPERM for lack of
privilege.
&mac.mpo;_check_vnode_setmode
int
&mac.mpo;_check_vnode_setmode
struct ucred
*cred
struct vnode
*vp
struct label
*label
mode_t mode
&mac.thead;
cred
Subject credential
vp
Object; vnode
label
Policy label for vp
mode
File mode; see &man.chmod.2;
Determine whether the subject credential can set the
passed mode on the passed vnode. Return
0 for success, or an
errno value for failure. Suggested
failure: EACCES for label mismatch,
or EPERM for lack of
privilege.
&mac.mpo;_check_vnode_setowner
int
&mac.mpo;_check_vnode_setowner
struct ucred
*cred
struct vnode
*vp
struct label
*label
uid_t uid
gid_t gid
&mac.thead;
cred
Subject credential
vp
Object; vnode
label
Policy label for vp
uid
User ID
gid
Group ID
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 (-1)
to request no update. Return 0
for success, or an errno value for
failure. Suggested failure: EACCES
for label mismatch, or EPERM for lack
of privilege.
&mac.mpo;_check_vnode_setutimes
int
&mac.mpo;_check_vnode_setutimes
struct ucred
*cred
struct vnode
*vp
struct label
*label
struct timespec
atime
struct timespec
mtime
&mac.thead;
cred
Subject credential
vp
Object; vp
label
Policy label for
vp
atime
Access time; see &man.utimes.2;
mtime
Modification time; see &man.utimes.2;
Determine whether the subject credential can set the
passed access timestamps on the passed vnode. Return
0 for success, or an
errno value for failure. Suggested
failure: EACCES for label mismatch,
or EPERM for lack of
privilege.
&mac.mpo;_check_proc_sched
int
&mac.mpo;_check_proc_sched
struct ucred
*ucred
struct proc
*proc
&mac.thead;
cred
Subject credential
proc
Object; process
Determine whether the subject credential can change the
scheduling parameters of the passed process. Return
0 for success, or an
errno value for failure. Suggested
failure: EACCES for label mismatch,
EPERM for lack of privilege, or
ESRCH to limit visibility.
See &man.setpriority.2; for more information.
&mac.mpo;_check_proc_signal
int
&mac.mpo;_check_proc_signal
struct ucred
*cred
struct proc
*proc
int signal
&mac.thead;
cred
Subject credential
proc
Object; process
signal
Signal; see &man.kill.2;
Determine whether the subject credential can deliver the
passed signal to the passed process. Return
0 for success, or an
errno value for failure. Suggested
failure: EACCES for label mismatch,
EPERM for lack of privilege, or
ESRCH to limit visibility.
&mac.mpo;_check_vnode_stat
int
&mac.mpo;_check_vnode_stat
struct ucred
*cred
struct vnode
*vp
struct label
*label
&mac.thead;
cred
Subject credential
vp
Object; vnode
label
Policy label for
vp
Determine whether the subject credential can
stat the passed vnode. Return
0 for success, or an
errno value for failure. Suggested
failure: EACCES for label mismatch,
or EPERM for lack of
privilege.
See &man.stat.2; for more information.
&mac.mpo;_check_ifnet_transmit
int
&mac.mpo;_check_ifnet_transmit
struct ucred
*cred
struct ifnet
*ifnet
struct label
*ifnetlabel
struct mbuf
*mbuf
struct label
*mbuflabel
&mac.thead;
cred
Subject credential
ifnet
Network interface
ifnetlabel
Policy label for
ifnet
mbuf
Object; mbuf to be sent
mbuflabel
Policy label for
mbuf
Determine whether the network interface can transmit the
passed mbuf. Return 0 for
success, or an errno value for failure.
Suggested failure: EACCES for label
mismatch, or EPERM for lack of
privilege.
&mac.mpo;_check_socket_deliver
int
&mac.mpo;_check_socket_deliver
struct ucred
*cred
struct ifnet
*ifnet
struct label
*ifnetlabel
struct mbuf
*mbuf
struct label
*mbuflabel
&mac.thead;
cred
Subject credential
ifnet
Network interface
ifnetlabel
Policy label for
ifnet
mbuf
Object; mbuf to be delivered
mbuflabel
Policy label for
mbuf
Determine whether the socket may receive the datagram
stored in the passed mbuf header. Return
0 for success, or an
errno value for failure. Suggested
failures: EACCES for label mismatch,
or EPERM for lack of
privilege.
&mac.mpo;_check_socket_visible
int
&mac.mpo;_check_socket_visible
struct ucred
*cred
struct socket
*so
struct label
*socketlabel
&mac.thead;
cred
Subject credential
Immutable
so
Object; socket
socketlabel
Policy label for
so
Determine whether the subject credential cred can "see"
the passed socket (socket) using
system monitoring functions, such as those employed by
&man.netstat.8; and &man.sockstat.1;. Return
0 for success, or an
errno value for failure. Suggested
failure: EACCES for label mismatches,
EPERM for lack of privilege, or
ESRCH to hide visibility.
&mac.mpo;_check_system_acct
int
&mac.mpo;_check_system_acct
struct ucred
*ucred
struct vnode
*vp
struct label
*vlabel
&mac.thead;
ucred
Subject credential
vp
Accounting file; &man.acct.5;
vlabel
Label associated with
vp
Determine whether the subject should be allowed to
enable accounting, based on its label and the label of the
accounting log file.
&mac.mpo;_check_system_nfsd
int
&mac.mpo;_check_system_nfsd
struct ucred
*cred
&mac.thead;
cred
Subject credential
Determine whether the subject should be allowed to call
&man.nfssvc.2;.
&mac.mpo;_check_system_reboot
int
&mac.mpo;_check_system_reboot
struct ucred
*cred
int howto
&mac.thead;
cred
Subject credential
howto
howto parameter from
&man.reboot.2;
Determine whether the subject should be allowed to
reboot the system in the specified manner.
&mac.mpo;_check_system_settime
int
&mac.mpo;_check_system_settime
struct ucred
*cred
&mac.thead;
cred
Subject credential
Determine whether the user should be allowed to set the
system clock.
&mac.mpo;_check_system_swapon
int
&mac.mpo;_check_system_swapon
struct ucred
*cred
struct vnode
*vp
struct label
*vlabel
&mac.thead;
cred
Subject credential
vp
Swap device
vlabel
Label associated with
vp
Determine whether the subject should be allowed to add
vp as a swap device.
&mac.mpo;_check_system_sysctl
int
&mac.mpo;_check_system_sysctl
struct ucred
*cred
int *name
u_int *namelen
void *old
size_t
*oldlenp
int inkernel
void *new
size_t newlen
&mac.thead;
cred
Subject credential
name
See &man.sysctl.3;
namelen
old
oldlenp
inkernel
Boolean; 1 if called from
kernel
new
See &man.sysctl.3;
newlen
Determine whether the subject should be allowed to make
the specified &man.sysctl.3; transaction.
Label Management Calls
Relabel events occur when a user process has requested
that the label on an object be modified. A two-phase update
occurs: first, an access control check will be performed to
determine if the update is both valid and permitted, and then
the update itself is performed via a separate entry point.
Relabel entry points typically accept the object, object label
reference, and an update label submitted by the process.
Memory allocation during relabel is discouraged, as relabel
calls are not permitted to fail (failure should be reported
earlier in the relabel check).
Userland Architecture
The TrustedBSD MAC Framework includes a number of
policy-agnostic elements, including MAC library interfaces
for abstractly managing labels, modifications to the system
credential management and login libraries to support the
assignment of MAC labels to users, and a set of tools to
monitor and modify labels on processes, files, and network
interfaces. More details on the user architecture will
be added to this section in the near future.
APIs for Policy-Agnostic Label Management
The TrustedBSD MAC Framework provides a number of
library and system calls permitting applications to
manage MAC labels on objects using a policy-agnostic
interface. This permits applications to manipulate
labels for a variety of policies without being
written to support specific policies. These interfaces
are used by general-purpose tools such as &man.ifconfig.8;,
&man.ls.1; and &man.ps.1; to view labels on network
interfaces, files, and processes. The APIs also support
MAC management tools including &man.getfmac.8;,
&man.getpmac.8;, &man.setfmac.8;, &man.setfsmac.8;,
and &man.setpmac.8;. The MAC APIs are documented in
&man.mac.3;.
Applications handle MAC labels in two forms: an
internalized form used to return and set labels on
processes and objects (mac_t),
and externalized form based on C strings appropriate for
storage in configuration files, display to the user, or
input from the user. Each MAC label contains a number of
elements, each consisting of a name and value pair.
Policy modules in the kernel bind to specific names
and interpret the values in policy-specific ways. In
the externalized string form, labels are represented
by a comma-delimited list of name and value pairs separated
by the / character. Labels may be
directly converted to and from text using provided APIs;
when retrieving labels from the kernel, internalized
label storage must first be prepared for the desired
label element set. Typically, this is done in one of
two ways: using &man.mac.prepare.3; and an arbitrary
list of desired label elements, or one of the variants
of the call that loads a default element set from the
&man.mac.conf.5; configuration file. Per-object
defaults permit application writers to usefully display
labels associated with objects without being aware of
the policies present in the system.
Currently, direct manipulation of label elements
other than by conversion to a text string, string editing,
and conversion back to an internalized label is not supported
by the MAC library. Such interfaces may be added in the
future if they prove necessary for application
writers.
Binding of Labels to Users
The standard user context management interface,
&man.setusercontext.3;, has been modified to retrieve
MAC labels associated with a user's class from
&man.login.conf.5;. These labels are then set along
with other user context when either
LOGIN_SETALL is specified, or when
LOGIN_SETMAC is explicitly
specified.
It is expected that, in a future version of FreeBSD,
the MAC label database will be separated from the
login.conf user class abstraction,
and be maintained in a separate database. However, the
&man.setusercontext.3; API should remain the same
following such a change.
Conclusion
The TrustedBSD MAC framework permits kernel modules to
augment the system security policy in a highly integrated
manner. They may do this based on existing object properties,
or based on label data that is maintained with the assistance of
the MAC framework. The framework is sufficiently flexible to
implement a variety of policy types, including information flow
security policies such as MLS and Biba, as well as policies
based on existing BSD credentials or file protections. Policy
authors may wish to consult this documentation as well as
existing security modules when implementing a new security
service.
diff --git a/en_US.ISO8859-1/books/arch-handbook/usb/chapter.sgml b/en_US.ISO8859-1/books/arch-handbook/usb/chapter.sgml
index 20402dba3f..2ae71a9d2c 100644
--- a/en_US.ISO8859-1/books/arch-handbook/usb/chapter.sgml
+++ b/en_US.ISO8859-1/books/arch-handbook/usb/chapter.sgml
@@ -1,649 +1,649 @@
Nick
Hibma
Written by
Murray
Stokely
Modifications for Handbook made by
USB Devices
Introduction
Universal Serial Bus (USB)
NetBSD
The Universal Serial Bus (USB) is a new way of attaching
devices to personal computers. The bus architecture features
two-way communication and has been developed as a response to
devices becoming smarter and requiring more interaction with the
host. USB support is included in all current PC chipsets and is
therefore available in all recently built PCs. Apple's
introduction of the USB-only iMac has been a major incentive for
hardware manufacturers to produce USB versions of their devices.
The future PC specifications specify that all legacy connectors
on PCs should be replaced by one or more USB connectors,
providing generic plug and play capabilities. Support for USB
hardware was available at a very early stage in NetBSD and was
developed by Lennart Augustsson for the NetBSD project. The
code has been ported to FreeBSD and we are currently maintaining
a shared code base. For the implementation of the USB subsystem
a number of features of USB are important.
Lennart Augustsson has done most of the implementation of
the USB support for the NetBSD project. Many thanks for this
incredible amount of work. Many thanks also to Ardy and Dirk for
their comments and proofreading of this paper.
Devices connect to ports on the computer
directly or on devices called hubs, forming a treelike device
structure.
The devices can be connected and disconnected at
run time.
Devices can suspend themselves and trigger
resumes of the host system
As the devices can be powered from the bus, the
host software has to keep track of power budgets for each
hub.
Different quality of service requirements by the
different device types together with the maximum of 126
devices that can be connected to the same bus, require proper
scheduling of transfers on the shared bus to take full
advantage of the 12Mbps bandwidth available. (over 400Mbps
with USB 2.0)
Devices are intelligent and contain easily
accessible information about themselves
The development of drivers for the USB subsystem and devices
connected to it is supported by the specifications that have
been developed and will be developed. These specifications are
publicly available from the USB home pages. Apple has been very
strong in pushing for standards based drivers, by making drivers
for the generic classes available in their operating system
MacOS and discouraging the use of separate drivers for each new
device. This chapter tries to collate essential information for a
basic understanding of the present implementation of the USB
stack in FreeBSD/NetBSD. It is recommended however to read it
together with the relevant specifications mentioned in the
references below.
Structure of the USB Stack
The USB support in FreeBSD can be split into three
layers. The lowest layer contains the host controller driver,
providing a generic interface to the hardware and its scheduling
facilities. It supports initialisation of the hardware,
scheduling of transfers and handling of completed and/or failed
transfers. Each host controller driver implements a virtual hub
providing hardware independent access to the registers
controlling the root ports on the back of the machine.
The middle layer handles the device connection and
disconnection, basic initialisation of the device, driver
selection, the communication channels (pipes) and does
resource management. This services layer also controls the
default pipes and the device requests transferred over
them.
The top layer contains the individual drivers supporting
specific (classes of) devices. These drivers implement the
protocol that is used over the pipes other than the default
pipe. They also implement additional functionality to make the
device available to other parts of the kernel or userland. They
use the USB driver interface (USBDI) exposed by the services
layer.
Host Controllers
USBhost controllers
The host controller (HC) controls the transmission of
packets on the bus. Frames of 1 millisecond are used. At the
start of each frame the host controller generates a Start of
Frame (SOF) packet.
The SOF packet is used to synchronise to the start of the
frame and to keep track of the frame number. Within each frame
packets are transferred, either from host to device (out) or
from device to host (in). Transfers are always initiated by the
host (polled transfers). Therefore there can only be one host
per USB bus. Each transfer of a packet has a status stage in
which the recipient of the data can return either ACK
(acknowledge reception), NAK (retry), STALL (error condition) or
nothing (garbled data stage, device not available or
disconnected). Section 8.5 of the USB
specification explains the details of packets in more
detail. Four different types of transfers can occur on a USB
bus: control, bulk, interrupt and isochronous. The types of
transfers and their characteristics are described below (`Pipes'
subsection).
Large transfers between the device on the USB bus and the
device driver are split up into multiple packets by the host
controller or the HC driver.
Device requests (control transfers) to the default endpoints
are special. They consist of two or three phases: SETUP, DATA
(optional) and STATUS. The set-up packet is sent to the
device. If there is a data phase, the direction of the data
packet(s) is given in the set-up packet. The direction in the
status phase is the opposite of the direction during the data
phase, or IN if there was no data phase. The host controller
hardware also provides registers with the current status of the
root ports and the changes that have occurred since the last
reset of the status change register. Access to these registers
is provided through a virtualised hub as suggested in the USB
specification [ 2]. The virtual hub must comply with the hub
device class given in chapter 11 of that specification. It must
provide a default pipe through which device requests can be sent
to it. It returns the standard andhub class specific set of
descriptors. It should also provide an interrupt pipe that
reports changes happening at its ports. There are currently two
specifications for host controllers available: Universal
Host Controller Interface (UHCI; Intel) and Open
Host Controller Interface (OHCI; Compaq, Microsoft,
National Semiconductor). The UHCI specification has been
designed to reduce hardware complexity by requiring the host
controller driver to supply a complete schedule of the transfers
for each frame. OHCI type controllers are much more independent
- by providing a more abstract interface doing alot of work
+ by providing a more abstract interface doing a lot of work
themselves.
UHCI
USBUHCI
The UHCI host controller maintains a framelist with 1024
pointers to per frame data structures. It understands two
different data types: transfer descriptors (TD) and queue
heads (QH). Each TD represents a packet to be communicated to
or from a device endpoint. QHs are a means to groupTDs (and
QHs) together.
Each transfer consists of one or more packets. The UHCI
driver splits large transfers into multiple packets. For every
transfer, apart from isochronous transfers, a QH is
allocated. For every type of transfer these QHs are collected
at a QH for that type. Isochronous transfers have to be
executed first because of the fixed latency requirement and
are directly referred to by the pointer in the framelist. The
last isochronous TD refers to the QH for interrupt transfers
for that frame. All QHs for interrupt transfers point at the
QH for control transfers, which in turn points at the QH for
bulk transfers. The following diagram gives a graphical
overview of this:
This results in the following schedule being run in each
frame. After fetching the pointer for the current frame from
the framelist the controller first executes the TDs for all
the isochronous packets in that frame. The last of these TDs
refers to the QH for the interrupt transfers for
thatframe. The host controller will then descend from that QH
to the QHs for the individual interrupt transfers. After
finishing that queue, the QH for the interrupt transfers will
refer the controller to the QH for all control transfers. It
will execute all the subqueues scheduled there, followed by
all the transfers queued at the bulk QH. To facilitate the
handling of finished or failed transfers different types of
interrupts are generated by the hardware at the end of each
frame. In the last TD for a transfer the Interrupt-On
Completion bit is set by the HC driver to flag an interrupt
when the transfer has completed. An error interrupt is flagged
if a TD reaches its maximum error count. If the short packet
detect bit is set in a TD and less than the set packet length
is transferred this interrupt is flagged to notify
the controller driver of the completed transfer. It is the host
controller driver's task to find out which transfer has
completed or produced an error. When called the interrupt
service routine will locate all the finished transfers and
call their callbacks.
See for a more elaborate description the UHCI
specification.
OHCI
USBOHCI
Programming an OHCI host controller is much simpler. The
controller assumes that a set of endpoints is available, and
is aware of scheduling priorities and the ordering of the
types of transfers in a frame. The main data structure used by
the host controller is the endpoint descriptor (ED) to which
- aqueue of transfer descriptors (TDs) is attached. The ED
+ a queue of transfer descriptors (TDs) is attached. The ED
contains the maximum packet size allowed for an endpoint and
the controller hardware does the splitting into packets. The
pointers to the data buffers are updated after each transfer
and when the start and end pointer are equal, the TD is
retired to the done-queue. The four types of endpoints have
their own queues. Control and bulk endpoints are queued each at
their own queue. Interrupt EDs are queued in a tree, with the
level in the tree defining the frequency at which they
run.
framelist interruptisochronous control bulk
The schedule being run by the host controller in each
frame looks as follows. The controller will first run the
non-periodic control and bulk queues, up to a time limit set
by the HC driver. Then the interrupt transfers for that frame
number are run, by using the lower five bits of the frame
number as an index into level 0 of the tree of interrupts
EDs. At the end of this tree the isochronous EDs are connected
and these are traversed subsequently. The isochronous TDs
contain the frame number of the first frame the transfer
should be run in. After all the periodic transfers have been
run, the control and bulk queues are traversed
again. Periodically the interrupt service routine is called to
process the done queue and call the callbacks for each
transfer and reschedule interrupt and isochronous
endpoints.
See for a more elaborate description the
OHCI specification. Services layer The middle layer
provides access to the device in a controlled way and
maintains resources in use by the different drivers and the
services layer. The layer takes care of the following
aspects:
The device configuration
information
The pipes to communicate with a
device
Probing and attaching and detaching form a
device.
USB Device Information
Device configuration information
Each device provides different levels of configuration
information. Each device has one or more configurations, of
which one is selected during probe/attach. A configuration
provides power and bandwidth requirements. Within each
configuration there can be multiple interfaces. A device
interface is a collection of endpoints. For example USB
speakers can have an interface for the audio data (Audio
Class) and an interface for the knobs, dials and buttons (HID
Class). All interfaces in a configuration are active at the
same time and can be attached to by different drivers. Each
interface can have alternates, providing different quality of
service parameters. In for example cameras this is used to
provide different frame sizes and numbers of frames per
second.
Within each interface 0 or more endpoints can be
specified. Endpoints are the unidirectional access points for
communicating with a device. They provide buffers to
temporarily store incoming or outgoing data from the
device. Each endpoint has a unique address within
a configuration, the endpoint's number plus its direction. The
default endpoint, endpoint 0, is not part of any interface and
available in all configurations. It is managed by the services
layer and not directly available to device drivers.
Level 0 Level 1 Level 2 Slot 0
Slot 3 Slot 2 Slot 1
(Only 4 out of 32 slots shown)
This hierarchical configuration information is described
in the device by a standard set of descriptors (see section 9.6
of the USB specification [ 2]). They can be requested through
the Get Descriptor Request. The services layer caches these
descriptors to avoid unnecessary transfers on the USB
bus. Access to the descriptors is provided through function
calls.
Device descriptors: General information about
the device, like Vendor, Product and Revision Id, supported
device class, subclass and protocol if applicable, maximum
packet size for the default endpoint, etc.
Configuration descriptors: The number of
interfaces in this configuration, suspend and resume
functionality supported and power
requirements.
Interface descriptors: interface class,
subclass and protocol if applicable, number of alternate
settings for the interface and the number of
endpoints.
Endpoint descriptors: Endpoint address,
direction and type, maximum packet size supported and
polling frequency if type is interrupt endpoint. There is no
descriptor for the default endpoint (endpoint 0) and it is
never counted in an interface descriptor.
String descriptors: In the other descriptors
string indices are supplied for some fields.These can be
used to retrieve descriptive strings, possibly in multiple
languages.
Class specifications can add their own descriptor types
that are available through the GetDescriptor Request.
Pipes Communication to end points on a device flows
through so-called pipes. Drivers submit transfers to endpoints
to a pipe and provide a callback to be called on completion or
failure of the transfer (asynchronous transfers) or wait for
completion (synchronous transfer). Transfers to an endpoint
are serialised in the pipe. A transfer can either complete,
fail or time-out (if a time-out has been set). There are two
types of time-outs for transfers. Time-outs can happen due to
time-out on the USBbus (milliseconds). These time-outs are
seen as failures and can be due to disconnection of the
device. A second form of time-out is implemented in software
and is triggered when a transfer does not complete within a
specified amount of time (seconds). These are caused by a
device acknowledging negatively (NAK) the transferred
packets. The cause for this is the device not being ready to
receive data, buffer under- or overrun or protocol
errors.
If a transfer over a pipe is larger than the maximum
packet size specified in the associated endpoint descriptor,
the host controller (OHCI) or the HC driver (UHCI) will split
the transfer into packets of maximum packet size, with the
last packet possibly smaller than the maximum
packet size.
Sometimes it is not a problem for a device to return less
data than requested. For example abulk-in-transfer to a modem
might request 200 bytes of data, but the modem has only 5
bytes available at that time. The driver can set the short
packet (SPD) flag. It allows the host controller to accept a
packet even if the amount of data transferred is less than
requested. This flag is only valid for in-transfers, as the
amount of data to be sent to a device is always known
beforehand. If an unrecoverable error occurs in a device
during a transfer the pipe is stalled. Before any more data is
accepted or sent the driver needs to resolve the cause of the
stall and clear the endpoint stall condition through send the
clear endpoint halt device request over the default
pipe. The default endpoint should never stall.
There are four different types of endpoints and
corresponding pipes: - Control pipe / default pipe: There is
one control pipe per device, connected to the default endpoint
(endpoint 0). The pipe carries the device requests and
associated data. The difference between transfers over the
default pipe and other pipes is that the protocol for
the transfers is described in the USB specification [ 2]. These
requests are used to reset and configure the device. A basic
set of commands that must be supported by each device is
provided in chapter 9 of the USB specification [ 2]. The
commands supported on this pipe can be extended by a device
class specification to support additional
functionality.
Bulk pipe: This is the USB equivalent to a raw
transmission medium.
Interrupt pipe: The host sends a request for
data to the device and if the device has nothing to send, it
will NAK the data packet. Interrupt transfers are scheduled
at a frequency specified when creating the
pipe.
Isochronous pipe: These pipes are intended for
isochronous data, for example video or audio streams, with
fixed latency, but no guaranteed delivery. Some support for
pipes of this type is available in the current
implementation. Packets in control, bulk and interrupt
transfers are retried if an error occurs during transmission
or the device acknowledges the packet negatively (NAK) due to
for example lack of buffer space to store the incoming
data. Isochronous packets are however not retried in case of
failed delivery or NAK of a packet as this might violate the
timing constraints.
The availability of the necessary bandwidth is calculated
during the creation of the pipe. Transfers are scheduled within
frames of 1 millisecond. The bandwidth allocation within a
frame is prescribed by the USB specification, section 5.6 [
2]. Isochronous and interrupt transfers are allowed to consume
up to 90% of the bandwidth within a frame. Packets for control
and bulk transfers are scheduled after all isochronous and
interrupt packets and will consume all the remaining
bandwidth.
More information on scheduling of transfers and bandwidth
reclamation can be found in chapter 5of the USB specification
[ 2], section 1.3 of the UHCI specification [ 3] and section
3.4.2 of the OHCI specification [4].
Device probe and attach
USBprobe
After the notification by the hub that a new device has been
connected, the service layer switches on the port, providing the
device with 100 mA of current. At this point the device is in
its default state and listening to device address 0. The
services layer will proceed to retrieve the various descriptors
through the default pipe. After that it will send a Set Address
request to move the device away from the default device address
(address 0). Multiple device drivers might be able to support
the device. For example a modem driver might be able to support
an ISDN TA through the AT compatibility interface. A driver for
that specific model of the ISDN adapter might however be able to
provide much better support for this device. To support this
flexibility, the probes return priorities indicating their level
of support. Support for a specific revision of a product ranks
the highest and the generic driver the lowest priority. It might
also be that multiple drivers could attach to one device if
there are multiple interfaces within one configuration. Each
driver only needs to support a subset of the interfaces.
The probing for a driver for a newly attached device checks
first for device specific drivers. If not found, the probe code
iterates over all supported configurations until a driver
attaches in a configuration. To support devices with multiple
drivers on different interfaces, the probe iterates over all
interfaces in a configuration that have not yet been claimed by
a driver. Configurations that exceed the power budget for the
hub are ignored. During attach the driver should initialise the
device to its proper state, but not reset it, as this will make
the device disconnect itself from the bus and restart the
probing process for it. To avoid consuming unnecessary bandwidth
should not claim the interrupt pipe at attach time, but
should postpone allocating the pipe until the file is opened and
the data is actually used. When the file is closed the pipe
should be closed again, even though the device might still be
attached.
Device disconnect and detach
USBdisconnect
A device driver should expect to receive errors during any
transaction with the device. The design of USB supports and
encourages the disconnection of devices at any point in
time. Drivers should make sure that they do the right thing
when the device disappears.
Furthermore a device that has been disconnected and
reconnected will not be reattached at the same device
instance. This might change in the future when more devices
support serial numbers (see the device descriptor) or other
means of defining an identity for a device have been
developed.
The disconnection of a device is signaled by a hub in the
interrupt packet delivered to the hub driver. The status
change information indicates which port has seen a connection
change. The device detach method for all device drivers for
the device connected on that port are called and the structures
cleaned up. If the port status indicates that in the mean time
a device has been connected to that port, the procedure for
probing and attaching the device will be started. A device
reset will produce a disconnect-connect sequence on the hub
and will be handled as described above.
USB Drivers Protocol Information
The protocol used over pipes other than the default pipe is
undefined by the USB specification. Information on this can be
found from various sources. The most accurate source is the
developer's section on the USB home pages [ 1]. From these pages
a growing number of deviceclass specifications are
available. These specifications specify what a compliant device
should look like from a driver perspective, basic functionality
it needs to provide and the protocol that is to be used over the
communication channels. The USB specification [ 2] includes the
description of the Hub Class. A class specification for Human
Interface Devices (HID) has been created to cater for keyboards,
tablets, bar-code readers, buttons, knobs, switches, etc. A
third example is the class specification for mass storage
devices. For a full list of device classes see the developers
section on the USB home pages [ 1].
For many devices the protocol information has not yet been
published however. Information on the protocol being used might
be available from the company making the device. Some companies
will require you to sign a Non -Disclosure Agreement (NDA)
before giving you the specifications. This in most cases
precludes making the driver open source.
Another good source of information is the Linux driver
sources, as a number of companies have started to provide drivers
for Linux for their devices. It is always a good idea to contact
the authors of those drivers for their source of
information.
Example: Human Interface Devices The specification for the
Human Interface Devices like keyboards, mice, tablets, buttons,
dials,etc. is referred to in other device class specifications
and is used in many devices.
For example audio speakers provide endpoints to the digital
to analogue converters and possibly an extra pipe for a
microphone. They also provide a HID endpoint in a separate
interface for the buttons and dials on the front of the
device. The same is true for the monitor control class. It is
straightforward to build support for these interfaces through
the available kernel and userland libraries together with the
HID class driver or the generic driver. Another device that
serves as an example for interfaces within one configuration
driven by different device drivers is a cheap keyboard with
built-in legacy mouse port. To avoid having the cost of
including the hardware for a USB hub in the device,
manufacturers combined the mouse data received from the PS/2 port
on the back of the keyboard and the key presses from the keyboard
into two separate interfaces in the same configuration. The
mouse and keyboard drivers each attach to the appropriate
interface and allocate the pipes to the two independent
endpoints.
USBfirmware
Example: Firmware download Many devices that have been
developed are based on a general purpose processor with
an additional USB core added to it. Because the development of
drivers and firmware for USB devices is still very new, many
devices require the downloading of the firmware after they
have been connected.
The procedure followed is straightforward. The device
identifies itself through a vendor and product Id. The first
driver probes and attaches to it and downloads the firmware into
it. After that the device soft resets itself and the driver is
detached. After a short pause the device announces its presence
on the bus. The device will have changed its
vendor/product/revision Id to reflect the fact that it has been
supplied with firmware and as a consequence a second driver will
probe it and attach to it.
An example of these types of devices is the ActiveWire I/O
board, based on the EZ-USB chip. For this chip a generic firmware
downloader is available. The firmware downloaded into the
ActiveWire board changes the revision Id. It will then perform a
soft reset of the USB part of the EZ-USB chip to disconnect from
the USB bus and again reconnect.
Example: Mass Storage Devices Support for mass storage
devices is mainly built around existing protocols. The Iomega
USB Zipdrive is based on the SCSI version of their drive. The
SCSI commands and status messages are wrapped in blocks and
transferred over the bulk pipes to and from the device,
emulating a SCSI controller over the USB wire. ATAPI and UFI
commands are supported in a similar fashion.
ATAPI
The Mass Storage Specification supports 2 different types of
wrapping of the command block.The initial attempt was based on
sending the command and status through the default pipe and
using bulk transfers for the data to be moved between the host
and the device. Based on experience a second approach was
designed that was based on wrapping the command and status
blocks and sending them over the bulk out and in endpoint. The
specification specifies exactly what has to happen when and what
has to be done in case an error condition is encountered. The
biggest challenge when writing drivers for these devices is to
fit USB based protocol into the existing support for mass storage
devices. CAM provides hooks to do this in a fairly straight
forward way. ATAPI is less simple as historically the IDE
interface has never had many different appearances.
The support for the USB floppy from Y-E Data is again less
straightforward as a new command set has been designed.