May 2003
This paper mainly tells the new important security mechanism in the FreeBSD 5.0 operating system, ie forces the use of the forced access control mechanism (MAC), mainly including the forced access control framework and multi-level security (MLS) policy two parts. This part analyzes the source code of the MAC framework and MLS strategy over the systematically.
2 MAC framework and MLS strategic source code analysis The source code files related to this article mainly have two, namely /usr/src/sys/kern/kern_mac.c and /usr/src/sys/security/mac_mls/mac_mls.c. There are also some headers such as mac.h, mac_policy.h, etc.
2.1 MAC Frame Overall Structure The following is a schematic structural diagram of the Mac framework. When the user console or user program is accessed by the system call, the corresponding position in the kernel code is inserted into the Mac frame inspection function, and the kernel is inserted. The corresponding check function of the MAC framework will be called to do safety checks. The MAC framework will call each security policy on the Mac framework to determine if access is safe. In addition, other system events that may involve security issues, such as initializing various security tags, initializing various kernel objects, etc., will also notify the MAC framework, which makes corresponding processes.
From the figure we can also see that the security policy can be compiled independently of the kernel as a separate KLD module, and then hooks to the Mac framework when used. To determine if an access is secure, the Mac framework calls all security policies, and the Mac framework will only authorize this visit only when all security policies agree.
2.2 Safety Tag Safety Tags are a set of data defined by the MAC framework and individual security policies, which is used to describe the security information of the main body or object, and the security tag is stored in the kernel along other data of the kernel description host. To achieve enforce access control, you must first define security tags for the primary guest. Different strategies are different from the basis of judgment, and the possible definitions may not be the same. As a MAC framework, when the security policy is registered to it, it must attach the security tag used by the policy to each kernel object, so when you need to call the policy to provide security check, you can provide your own definition and Understanding safety tags. Let's give a secure tag definition defined by the MAC framework and the MLS policy, and further explain it.
The definition of security tags in the Mac framework is like this:
Struct label {
Int l_flags;
Union {
Void * l_ptr;
Long L_long;
} l_perpolicy [mac_max_policies];
}
Where l_flags is a flag, being used by the MAC framework to determine if the entire tag data structure is initialized. The L_PerPolicy array defines a joint for each policy so that when the policy is registered with the Mac framework, they can use a long-class integer as their own security tag, or use the joint pointer to a tag that they define themselves. data structure. MLS policies have selected the latter.
The security tag defined by the MLS policy is this:
STRUCT MAC_MLS_ELEMENT {
U_SHORT MME_TYPE;
U_SHORT MME_LEVEL;
U_CHAR MME_COMPARTMENTS [MAC_MLS_MAX_COMPARTMENTS >> 3];
}
Struct Mac_mls {
INT mm_flags;
STRUCT MAC_MLS_ELEMENT MM_SINGLE;
STRUCT MAC_MLS_ELEMENT MM_RANGELOW, MM_RANGEHIGH;
}
In the MAC_MLS structure, a single tag (mm_single) and one mark range (mm_rangelow, mm_rangehigh) are defined. The main guest can identify a single security level using a single mark, or the marker range can also be used to identify a security scope, or At the same time. As Chapter 1 we used the output "MLS / High" "MLS / High" to indicate that the file is a single security tag value "high". For example, we use the output of getPMAC "MLS / LOW-High" indicates that the process simultaneously uses a single tag and tag range. As for which tag is used, it is identified by the mm_flags. MAC_MLS_ELEMENT defines a tag, which is very powerful, supports the security type (MME_TYPE variable, value is Low, High, Equal, and undefine), also supports up to 256 levels of security level (when the value of MME_TYPE is Level The MME_LEVEL variable is valid, which is defined by it), and also uses the MME_Compartments array support domain (field), and the subsequent chapter describes how the MLS policy uses how it define it.
When the MLS policy is registered with the Mac framework, it uses a MAC tag one of the L_PrPolicy arrays, then pointing the L_PTR pointer to your defined Mac_mls structure, so that your defined tag is connected to each The kernel object is on.
2.3 MAC Framework Implementation Mac frame First, you must maintain a linked list to record all security policies hidden on it. This list is defined by the following code, and its meaning is no longer explained in detail. For details, see Kern_Mac.c: static list_head (, Mac_Policy_Conf) Mac_Policy_List;
The above code defines a Mac_Policy_Conf type linked list Mac_Policy_List, which is defined as follows:
Struct mac_policy_conf {
Char * mpc_name; / * policy name * /
Char * mpc_fullname; / * policy full name * /
Struct Mac_Policy_Ops * MPC_Ops; / * Policy Operations * /
INT MPC_LOADTIME_FLAGS; / * FLAGS * /
INT * MPC_Field_off; / * Security Field * /
INT MPC_Runtime_Flags; / * flags * /
List_entry (mac_policy_conf) MPC_List; / * Global List * /
}
The MPC_LIST member variable is a set of pointers to form a linked list. The most important member in the Mac_Policy_Conf structure is MPC_OPS, we talked, whenever access security check, the Mac framework will check all check events such as creating inode, accessing inode et al. to the security policy, this is MPC_OPS This member variable is carried out. That is, the MPC_OPS structure records the processing function of each policy to various MAC events. For example, the following is a function from kern_mac.c:
INT mac_check_vnode_open (struct ucred * cred, struct vNode * vp, int acid_mode) {
Int error;
Ask_VOP_LOCKED (VP, "Mac_Check_vnode_open");
IF (! mac_enforce_fs)
Return (0);
Mac_Check (Check_vnode_open, CRED, VP, & VP-> V_Label, ACC_MODE);
Return (Error);
}
When the user tries to open a file, the kernel will try to open a vNode, call this function before opening, and check if the main body has permission to open this vnode. Mac_Check macro is as follows:
#define mac_check (Check, Args ...) DO {/
Struct Mac_Policy_Conf * MPC; /
/
Error = 0; /
Mac_policy_list_busy (); /
List_foreach (MPC, & Mac_Policy_LIST, MPC_LIST) {/
IF (MPC-> MPC_Ops-> MPO_ ## Check! = null) /
Error = Error_Select (/
MPC-> MPC_Ops-> MPO_ ## Check (args), /
Error); /
} /
Mac_policy_list_unbusy (); /
} while (0)
We can see that using the list_foreach macro to traverse each policy in the security policy chain table, then call the check function MPO _ ## check registered in MPC_OPS. Mac_Policy_Ops defines a lot of event handlers in this structure, and the fine-grained access control is limited to the space, which is not listed here. These functions are divided into four categories: the first category is the initialization and destruction function of the policy itself; the second class is the operation function of the security tag, including the initialization and destruction functions of the security tag of various kernel objects, and the acquisition security tag Interface functions; third category is an event handler that operates on the mark of the file system, network system, and process object; the fourth class is an inspection function that checks if the access to each kernel object is safe. See Mac_Policy.h for details.
2.4 Registration Analysis of Security Policy MLS Policy, we can find that the security policy is a very simple thing to register to the Mac framework. A large amount of space in the Mac_mls.c file defines all event handlers, as mentioned earlier, these functions are the core of security policies, used to determine the security of access. After defining these functions, in the final code, the address of these functions is filled in the Mac_Policy_Ops structure, and then use a mac_policy_set macro to simmer the mac_policy_list linked list to the Mac_Policy_List linked list, as follows:
Mac_Policy_SET (& MAC_MLS_OPS, TRUSTEDBSD_MAC_MLS, "TrustedBSD Mac / MLS",
MPC_LoadTime_flag_notlate, & mac_mls_slot;
The MPC_LOADTIME_FLAG_NOTLATE flag tells the system that this KLD module can only load before system initialization, because MLS must attach its defined security tags for each object when initializing the system kernel object. Specifically, the system initializes all the kernel objects, will call the MPO_INIT_XXX_Label function defined in the Mac_Policy_Ops structure, and MLS is attached to its own mark in this function's tag. Let's analyze the Mac_Policy_set macro. #define mac_policy_set (MPOPS, MPNAME, MPFULLNAME, MPFLAGS, PrivData_WANTED) /
STATIC STRUCT MAC_POLICY_CONF MPNAME ## _ Mac_Policy_CONF = {/
#mpname, /
MpfullName, /
MPOPS, /
Mpflags, /
Privdata_wanted, /
0, /
}; /
Static moduleData_t mpname ## _ mod = {/
#mpname, /
Mac_Policy_ModEvent, /
& mpname ## _ mac_policy_conf /
}; /
Module_depend (Mpname, Kernel_Mac_support, 1, 1, 1); /
DECLARE_MODULE (MPNAME, MPNAME ## _ MOD, SI_SUB_MAC_POLICY, /
Si_order_middle)
Logic is also quite simple, let's go again. First define a mac_policy_conf structure, used to describe the MLS policy, and subsequent operations add this structure to the Mac_Policy_List list defined by the Mac framework. Since the MLS policy itself is a KLD module, you must define a moduleData_t structure to register the module to the system, indicate that the Mac_Policy_ModeVent function processing module event is indicated by the Mac_Policy_ModeVent function, and the Mac_Policy_CONF structure defined above is generated when there is a module event. Address transmission to the processing function.
The core code of the Mac_Policy_ModEvent function is as follows:
Case MOD_LOAD:
IF (MPC-> MPC_LOADTIME_FLAGS & MPC_LOADTIME_FLAG_NOTLATE &&
Mac_late) {
Printf ("Mac_Policy_Modevent: can't load% s policy"
"after booting / n", mpc-> mpc_name);
Error = ebusy;
Break;
}
Error = Mac_Policy_Register (MPC);
Break;
Case mod_unload:
/ * Don't unregister the module if it is never register. * /
IF ((MPC-> MPC_Runtime_Flags & MPC_Runtime_Flag_Register)
! = 0) Error = Mac_Policy_unregister (MPC);
Else
Error = 0;
Break;
When the module is loaded, the mac_policy_register function is called. It first checks if the module has been registered. If not, the following code will be executed: List_insert_Head (& Mac_Policy_LIST, MPC, MPC_List);
Where MPC is the address of the Mac_Policy_CONF structure mentioned above, so far, it is went in the policy list of the MLS policy to the mac framework.
2.5 MLS Strategy Source Code Analysis According to MLS policies, high security levels cannot write low security levels, while low-security levels cannot read high security levels, only the security level of the primary object is, can they read again write. MLS defines three tag comparison functions:
MAC_MLS_DOMINATE_SINGLE (A, B): The security level for checking whether a single tag of A is higher than the single tag of B. This function is mainly used to securely check for both read, write, query and other incidents of kernel variables. MAC_MLS_SINGLE_IN_RANGE (A, B): Used to check if a single-marked security level of A is bound to a secure level of the flag range of B. This function is mainly used to securely check the tag of the change kernel object. When the main body changes a security tag of the object, the security level of the newly marked is required to be within the security level of the main body. MAC_MLS_RANGE_IN_RANGE (A, B): It is within the security level of A to check if A is within the security level of B. This function is mainly used to change the subject security level, requiring the main new security level to fall within the current security level of the main body. MAC_MLS_EQUAL_SINGLE (A, B): Used to check if the security level of A and B is the same. This function is mainly used for network and device operations.
All the above functions are called the MAC_mls_dominate_element () function to be concremented. Let's take a look at this function, and its source code is as follows:
Static Int Mac_mls_dominate_element (Struct Mac_mls_element * a,
STRUCT MAC_MLS_ELEMENT * B)
{
Int bit;
Switch (A-> MME_TYPE) {
Case Mac_mls_type_equal:
Case Mac_mls_type_high:
Return (1);
Case Mac_mls_type_low:
Switch (B-> MME_TYPE) {
Case Mac_mls_type_level:
Case Mac_mls_type_high:
Return (0);
Case Mac_mls_type_equal:
Case Mac_mls_type_low:
Return (1);
DEFAULT:
PANIC ("MAC_MLS_DOMINATE_ELEMENT: B-> MME_TYPE INVALID");
}
Case Mac_mls_type_level:
Switch (B-> MME_TYPE) {
Case Mac_mls_type_equal:
Case Mac_mls_type_low:
Return (1);
Case Mac_mls_type_high:
Return (0);
Case Mac_mls_type_level:
FOR (bit = 1; bit <= mac_mls_max_compartments; bit )
IF (! mac_mls_bit_test (bit,
A-> MME_Compartments &&
Mac_mls_bit_test (bit, b-> mme_compartments) RETURN (0);
Return (A-> MME_LEVEL> = B-> MME_LEVEL);
DEFAULT:
PANIC ("MAC_MLS_DOMINATE_ELEMENT: B-> MME_TYPE INVALID");
}
DEFAULT:
PANIC ("MAC_MLS_DOMINATE_ELEMENT: A-> MME_TYPE INVALID");
}
Return (0);
}
We only explain the last case, that is, when the type A and B is Mac_mls_Type_LEVEL, that is, when they use a number (0 to 254) identifying their security level, it is determined how it is done. First of all:
#define mac_mls_bit_test (b, w) ((w) [((b) - 1) >> 3)] & (1 << (((b) - 1) & 7))))
We can see that the MME_Compartments are tested before comparing the security levels. MME_compartments is a 256bit data (defined by UCHAR [32]), each bit can be set to 1 to indicate a certain security domain, of course, can set multiple bits to indicate that this object belongs to multiple security domains. MLS requires that if A can access B, the security domain to which B will have to be a subset of A, otherwise access is rejected. The purpose of testing MME_Compartments is that it is to determine whether the BIT set in B is set in A.
2.6 Expansion of the Mac framework and MLS strategy We have improved the Mac framework. As mentioned earlier, the Mac framework currently does not support settings for the security level of the user, nor where the user security level information is provided, and we want to improve it to make it more practical. Our improvement is to intercept the SETUID system call of the system, when the system is setUID (user login, runs su command, etc.), read into the user security level information and set accordingly. We have done the following work:
Add a new function MPO_GET_CRED_FROM_FILE () in the mac_policy_ops structure in the mac_policy.h file, the parameters and return values are exactly the same as MPO_CREATE_CRED (). Add a new function MAC_MLS_GET_CRED_FROM_MLS_GET_CRED_FROM_FILE () in a mac_mls.c file, which is exactly the same as MAC_mls_create_cred (). In this function, add the statement to the kernel to read and write the user security level configuration file in the kernel, thereby reading the user's security level here. Then add a statement in the setting statement of the Mac_Policy_Ops structure: .mpo_get_cred_from_file = mac_mls_get_cred_from_file. In the setuid () function in the kern_prot.c file, the crcopy () function replaces our own mac_crcopy () function, and add a statement before calling this function: newcred-> cr_uid = uid ;. The code for the Mac_Crcopy () function is as follows:
Void Mac_Crcopy (Struct Ucred * Dest, Struct Ucred * SRC)
{
UID_T UID = DEST-> CR_UID;
Kassert (Crshared (DEST) == 0, ("crcopy of shared ucred");
BCOPY (& SRC-> CR_StartCopy, & dest-> CR_StartCopy, (Unsigned) ((CADDR_T) & SRC-> CR_ENDCOPY -
(CADDR_T) & SRC-> CR_StartCopy));
UIHOLD (DEST-> CR_UIDINFO);
UiHold (dest-> cr_ruidinfo);
IF (Jailed (DEST))
Prison_hold (dest-> cr_prison);
#ifdef mac
DEST-> CR_UID = UID;
Mac_get_cred (src, dest);
DEST-> CR_UID = SRC-> CR_UID;
#ENDIF
} Modify the corresponding header file and recompile the kernel.
2.7 Summary The main content of the Mac framework and MLS strategy is limited to the space, and we only give the main logic. If you want to know more detailed technical details, please read its source code or contact me. In addition, the MAC framework and MLS strategy have also used some important technologies, such as system control (SYSCTL) mechanisms, locks, etc., we have not mentioned that if interested readers can continue to study.
About the author Yi Xiaodong, Male, National Defense Technology University in the study direction is a safe operating system. You can contact him by email yi_xiao_dong@sohu.com