This paper analyzes the whole process of the MAC framework of FreeBSD 10.0 "http://xrefs.info/freebsd-10.0/".
There is a comment in "/USR/SRC/SYS/SECURITY/MAC/MAC_FRAMEWORK.C" that describes the three main features of the MAC Framework implementation:
In other words, 1) can implement different policy modules according to different security policies, and register with the MAC framework through the interface defined in <security/mac/mac_policy.h>, 2) Each kernel subsystem can pass < The interface defined in security/mac/mac_framework.h> to request the MAC framework for Security determination; 3) When a security decision request is received by the MAC framework The decision function of each policy module that has been registered is called sequentially, and the security decision is realized; 4) provides a user-space interface for setting the security properties of the managed resource object (label State).
Mac Code Layout
Overall, the Mac-related code for FreeBSD is located under the "/usr/src/sys/security/" directory. Where the Mac directory is the framework itself, the audit directory is the module responsible for security audits (Common criteria requirements), and other directories are implemented with different MAC policies.
Among them, the "/usr/src/sys/security/mac/" directory is as follows:
Visible:
- Mac_framework.h and mac_framework.c for Mac frames
- MAC_CRED.C Management code for the principal (user) credential
- MAC_LABEL.C Tag Management code for Mac
- Other files are interface codes for specific MAC controlled subsystems
Mac Framework Startup
The entry for the module is found by viewing the Sysinit () of the "/USR/SRC/SYS/SECURITY/MAC/MAC_FRAMEWORK.C" module as follows:
Therefore, Mac_init () is called first.
This module defines some of the module global variables, which are initialized here.
That is, the Mac policy module is divided into dynamic policy modules (which are linked into the mac_policy_list and need to be locked up over time) and static policy modules (chained into the mac_static_policy_list and do not need to be locked in the duration).
Mac Policy Registration
MAC policies are registered with the MAC framework via Mac_policy_register ().
The previous part of the Mac_policy_register () function:
The first is locking mac_policy_xlock (); Then determine whether the strategy is to link to a static linked list or link to a dynamic list (the principle is based on the dynamic policy module can be uninstalled, will be set Mpc_loadtime_flag_unloadok, and static policy can not be dynamically unloaded) And then determine if the policy is already on the linked list (to avoid repeating the same policy).
The second part of the function Mac_policy_register () is as follows:
The global variable mac_slot_offsets_free type is int, which limits support for up to 32 different policies, and the following comment explains the reason. Because the MAC framework maintains a bitmask, each registered MAC policy corresponds to a bit on that bitmask, and the bit is not recycled when unloaded, ensuring that these slots are not reused. This is a label-related design.
Therefore, the code for Mac_policy_register () finds the slot (slot) corresponding to the newly registered policy module based on the bitmask already set by the current Mac_slot_offsets_free variable. The mpc_runtime_flag_registered is then set to indicate that the policy has been registered and linked to the corresponding policy chain list. Each policy may have policy-specific initialization operations (used to initialize policy-specific data structures and functions), so the initialization function (Mpc->mpc_ops->mpo_init (MPC)) of the policy is called after the policy is chained to the linked list. The policy callback function here accepts the parameter MPC, which is a typical object-oriented operation model implemented in C language.
The call to Mac_policy_update () is critical before the call to Mac_policy_xunlock () is unlocked and returned.
Mac policy Update
The code for the function Mac_policy_update () is as follows:
It seems simple to empty and recalculate the Mac_policy_count global variable (in fact this variable does not need to be updated in this way, incrementing or decreasing the line directly in the Register or unload function) and the mac_labeled global variable (this is the necessary update, See the following analysis). For each policy on the dynamic policy list and the static policy list, call the mac_policy_getlabeled () function, which returns the value of the function "bitwise-and" to the mac_labeled global variable. This mac_labeled global variable is important, and the following note illustrates this. Each Mac policy "declares" a bitmask, which represents the policy requires that the "object type (Types)" be assigned a label. Note that the "declaration" here is not implemented by a definite struct field, but rather by examining which of the MAC policies implements the tag initialization (label init) callback function (see mac_policy_getlabeled ()). And this mac_labeled global variable is actually a sum of the bitmask of all policy "declarations".
The following is the code for the Mac_policy_getlabeled () function:
That is, each MAC policy can support ("interested") multiple "object types", and implement a label initialization (label Init) callback function that is related to that object type for the supported object types. Each object type corresponds to a bit bit (for example, Mpc_object_vnode), and the mac_policy_getlabeled () function returns uint64_t, so the system supports a maximum of 64 object types. Currently the system defines the following supported object types:
Once all the policies have been registered, the mac_labeled global variable is available to determine whether there is a Mac policy "interested" in the system for each type of object. In turn, each object type, when initializing an object of that type, has the ability to invoke the type-specific initialization function, which, based on the mac_labeled global variable, determines whether the object needs to be assigned a label. For example, for a file system's Vnode object type (corresponding to Mpc_object_vnode), there is a mac_vnode_init () function that can perform the assignment of the label of the Vnode object. The Mac_vnode_init () function is as follows:
The call to this function is in the Getnewvnode () function of the VFS:
Mac Tag Assignment
As mentioned earlier, if any of the MAC policies are interested in an object type, the object type has a label (associated) associated with the object (objects) that is "related to". Since there may be more than one Mac policy interested in an "object type", and an actual "object" has only one label associated with it, this determines that the label is "Universal (generic)", which is , that is, not a label corresponds to a Mac policy, but a label that corresponds to multiple MAC policies. Therefore, the definition of "label" is as follows:
As can be seen from the definition of this struct, a "label" is not specific to a Mac policy and is not specific to an "object type". However, when assigning a label for an object, you need to initialize the label to a label specific to that object type, according to the object's type. This initialization process is specific to this type of object, so only object-managed code of this object type knows how to manage the struct label structure. Because the struct lavel l_perpolicy[] array has mac_max_slots fields, it can be inferred that the object label management code for a type object assigns a data structure to each of the MAC policies that are "interested" in the object type. This data structure is specific to that object type and the Mac policy (thus establishing a one by one correspondence between an object and a Mac policy). Let's verify this guessing by using the Mac_vnode_init () function in the previous example to assign a label, which actually calls Mac_mount_label_alloc () to assign a label:
The Mac_labelzone_alloc () here only allocates a piece of memory (struct label) from a UMA zone dedicated to the label.
The actual initialization of this label is done in code Mac_policy_perform (Vnode_init_label, label). Mac_policy_perform () is defined as follows:
Therefore, Mac_policy_perform (Vnode_init_label, label) is actually the Mpo_vnode_init_label (label) callback function that calls the policy for all registered MAC policies, respectively. For this, our search can be informed that for Vnode object type, there are the following MAC policy implemented this callback function, so they are "interested" in Vnode mac policy.
Let's take a look at the Biba_init_label () function implemented in MAC_BIBA.C to see how a particular Mac policy Initializes a label (which should actually be the part that the label corresponds to that Mac policy).
and Slot_set () is defined as follows:
Obviously, the Slot_set () here is to set the pointer returned by Biba_alloc () to a label in the l_perpolicy[] array corresponding to the location of the Biba_slot.
And this biba_slot variable is derived from the following mac_policy_set ():
Remember that there was a segment code in the previous analysis of Mac_policy_register () to get the slot slot number corresponding to this registered MAC policy?
The resulting slot number is set to the address of mpc->mpc_field_off, so the value of the global variable Biba_slot is actually updated for the Mac_biba strategy. So when is the Mac_biba strategy called to Mac_policy_register ()? This goes back to the question of how FreeBSD initializes the module. Below is
Check again to Mac_policy_set () that there are Declare_module (Mpname, mpname# #_mod, Si_sub_mac_policy, I_order_middle) to know that this is actually static moduledata_t mpname# #_mod中指定了mac_policy_modevent () as a callback function for module loading or unloading, so in fact, in the early initialization of FreeBSD module initialization, it will follow si_sub_mac_ The I_order_middle order of the policy subsystem initializes each module, allowing Mac_policy_register () to be called.
Now go back to Biba_alloc ():
As we have guessed earlier, this is to assign a data structure specific to the MAC policy of Biba, the struct Mac_biba, and the assigned pointer to the struct will be stored in the l_perpolicy[] array of the struct label corresponding to the Biba_ The location of the slot. With the binding relationship between this data structure, when you want to perform a security policy check on an object, it is possible to find the object's struct Mac_biba by the l_perpolicy[] array for that policy. Let's see if this is the case.
Mac Policy Check
We still use the Vnode object type as an example to analyze how the MAC policy carries out security checks. As shown in the following, a series of check entry functions for Vnode are implemented in "/USR/SRC/SYS/SECURITY/MAC/MAC_VFS.C", which are inspection portals for different ways of accessing Vnode.
For example, the Mac_vnode_check_open () function is called at the following location:
Where the call in "/USR/SRC/SYS/KERN/VFS_VNOPS.C" is as follows:
So back to Mac_vnode_check_open (), let's see exactly how it's checked:
In fact, all of these security checkpoints, although the number of parameters are different, but there is a common rule is that there is a struct ucred struct pointer parameters (such as the cred here), there is a current access to the "object" pointer (such as the VP here), The other is the auxiliary parameters associated with it (for example, Accmode here).
We see that this is actually called the Mac_policy_check () macro:
The first parameter of the Mac_policy_check () macro is the mark of the check to be performed (for example, the Vnode_check_open in this case), which is a combination of the related operations within the macro and the mpc_ops that is spelled out specifically to execute the callback function. For example, this is spelled out Mpc->mpo_ops->mpo_vnode_check_open_check (). As a result, Mac_policy_check () is actually going to perform all the policy checks on an object type. For the Mac_biba strategy, this function is Biba_vnode_check_open ():
For the time being, we do not consider how a particular strategy determines whether an access is considered safe (i.e., temporarily without a specific policy principle), but only how to find the basis of judgment from specific visits (that is, what resources determine whether it is secure). Analyzing the above example, we can see:
- The current access principal (subject) is derived from the parameter cred, which is the user's corresponding label, such as Cred->cr_label here, and the specific data related to this principal and Mac policy in this tag, such as the struct Mac_biba *SUBJ.
- The object's "label" can be found from the Access object (such as the VP here), and the object corresponds to the specific data related to the MAC policy, such as the struct Mac_biba * obj here.
- With these two specific data specific to the principal and object about the Mac policy, it is possible to follow the rules of the policy to determine if the access is secure.
If this access is judged to be unsafe, then this judgment function returns eaccess (or any other error), otherwise returns 0. Then, the corresponding object may have more than one Mac policy to check, then if any one of the policy checks have failed, this return value will be used as the first parameter of Mac_error_select (), and the result of the previous check as the second parameter of Mac_error_select (), The decision to make the highest-priority error. Finally, all the return values after the completion of the decision are returned to the caller as the total result of this access security, and the caller ultimately decides whether to allow this access.
?
?
?
?
?
TrustedBSD Mandatory Access Control Framework Analysis