Synopsis #
FreeBSD Mandatory Access Control (MAC) policies add kernel-enforced decisions to the ordinary discretionary access control (DAC) model. They are appropriate when a specific resource or information-flow rule cannot be expressed reliably with users, groups, modes, ACLs, jails, service privilege separation, or firewall policy alone.
MAC is a framework, not one universal hardening mode. Its policy modules solve different problems, and several use labels whose design affects files, processes, login classes, and recovery. Loading every policy does not create a coherent security model. Begin with a written rule, choose the narrowest module that enforces it, and qualify both intended access and intended denial on a representative non-production system.
Start with the rule, not the module #
A MAC proposal should identify:
- the subjects whose actions need control, such as service accounts or user classes;
- the objects or resources being protected;
- the access or information flow that must be allowed;
- the access that must be denied even when ordinary ownership permits it;
- who may administer the policy and through which recovery path;
- how the decision will be tested after upgrades.
“Enable MAC” is not a security requirement. “Only the account with UID 1001 may bind TCP port 80” is a testable rule. “Project A data must never be read by Project B” is also testable, but requires a substantially larger classification and labeling design.
First establish the security baseline . An unsupported release, excess listener, weak account boundary, or missing recovery path should not be hidden behind a more complicated access-control layer.
Understand how MAC composes with DAC #
DAC uses ownership, groups, modes, and ACLs. Owners have discretion over much of that state. A MAC policy adds a system-administered check that subjects normally cannot relax at will.
Access must pass the applicable checks. A MAC allow rule does not grant access that DAC denies, and a permissive file mode does not bypass a MAC denial. When several MAC policies are active, their restrictions compose; one policy does not cancel another policy’s denial.
The root boundary depends on the policy. Some modules have explicit superuser exemptions, while labeled policies can constrain actions that would otherwise pass ordinary DAC checks. The system administrator can still control policy configuration in many designs, and the MAC framework does not cover every possible channel. It should not be relied on alone to contain a malicious privileged administrator.
Prefer a simpler boundary when it expresses the rule #
Use ordinary mechanisms when they provide the required invariant with less recovery risk:
| Requirement | Usually consider first |
|---|---|
| Separate one service from the host | A jail, dedicated account, filesystem permissions, and a narrow network policy |
| Prevent one account from modifying another account’s files | Ownership, groups, modes, or POSIX ACLs |
| Hide an administrative service from untrusted networks | Service binding and firewall policy |
| Drop application privilege after binding or initialization | The application’s documented privilege-separation model |
| Restrict CPU, memory, or process counts | Jail and resource-control facilities |
| Record security-relevant actions | FreeBSD security event auditing rather than an access-control policy |
The jail decision guide distinguishes operating-system isolation from a virtual machine boundary. A jail and a MAC policy can be composed, but neither should be added without a separate purpose.
Match the policy family to the requirement #
The following map is a selection aid, not a ready-made configuration:
| Policy | Narrow purpose | Important design boundary |
|---|---|---|
mac_portacl(4) | Permit named numeric identities to bind selected TCP or UDP ports | Composes with the ordinary reserved-port restriction; rules replace the complete list |
mac_seeotheruids(4) | Limit visibility of processes and sockets owned by other users | Group exemptions and operational monitoring must be planned |
mac_bsdextended(4) | Apply UID/GID-based rules to filesystem access | Rule order, default behavior, and root handling require negative tests |
mac_ifoff(4) | Prevent use of selected interface classes | A wrong value can remove loopback or network recovery access |
mac_partition(4) | Divide process visibility into numeric partitions | It is process partitioning, not filesystem or network isolation |
mac_mls(4) | Enforce confidentiality levels and compartments | Requires a complete secrecy and labeling model |
mac_biba(4) | Enforce integrity levels and compartments | Information-flow rules may conflict with ordinary administration |
mac_lomac(4) | Protect integrity through a low-watermark model | Subjects may have their integrity level demoted after reading lower-integrity data |
Testing and stub modules such as mac_test(4), mac_stub(4), and mac_none(4) are not production security policies.
For the narrow reserved-port case, use Bind a service to a low port without running it as root
. That guide treats mac_portacl, the traditional reserved-port check, service identity, persistence, and rollback as one composed change.
Distinguish module, policy, labels, and persistence #
Four different states can be involved:
- The kernel contains the MAC framework. GENERIC includes it on supported FreeBSD releases covered here.
- A policy module is built into the kernel or loaded dynamically.
- The policy’s enforcement settings, rule set, or labels express the local security design.
- Boot and login configuration recreate that design after restart.
Loading a module is not equivalent to completing the policy. Some non-labeling policies begin enforcing defaults as soon as they load. Labeled policies may require filesystem support, object labels, login-class labels, and interface labels before ordinary services work correctly.
Do not compile policy modules into a custom kernel merely because a loader setting appears less permanent. A static policy is harder to remove during recovery. The kernel mechanism guide describes when static configuration is justified.
Qualify a policy before production #
Use a disposable or representative staging system with the same filesystem types, login paths, service accounts, jails, remote administration, and boot arrangement. A useful test matrix includes:
| Test | Expected evidence |
|---|---|
| Intended access | The normal workload completes under the real service identity |
| Intended denial | A separate identity is denied by the MAC check being evaluated |
| Root administration | Documented maintenance actions behave according to the design |
| Service startup | Required labels, rules, and policy modules exist before the service starts |
| Login and privilege transition | Console, SSH, su, and other approved paths retain the correct identity and label |
| Backup and restore | Restored data preserves or deliberately recreates required labels and attributes |
| Upgrade | A release update or representative reboot preserves enforcement and service availability |
| Recovery | The policy can be bypassed or corrected from the available console path |
Test denials as deliberately as successful actions. A service that starts proves availability, not that the unwanted action is blocked. A denial message also does not prove the intended policy caused it; ordinary DAC, jail, or firewall controls may have rejected the operation first.
Plan recovery before persistence #
Capture the existing module list, policy sysctls, login-class configuration, filesystem options, and labels relevant to the proposed policy. Keep an out-of-band console available. A remote shell on the interface or account being restricted is not a recovery path.
Introduce one policy at a time and avoid permanent boot configuration until runtime behavior has been qualified where the module permits such testing. Do not assume unloading a module reverses its work. A module may be busy, a service may retain state created before enforcement, and object labels can outlive the module load that created them.
For a failed non-labeling policy test, restore the known rules and enforcement values before attempting a broader rule. For a failed labeling design, stop and use the documented single-user or console recovery procedure. Removing enforcement without reconciling /etc/login.conf, filesystem labels, or policy-specific configuration can leave identities and objects inconsistent.
Every accepted deployment should retain:
- the written rule and threat it addresses;
- the policy module and every local setting;
- the positive and negative test cases;
- the authorized policy administrator;
- console and boot recovery steps;
- a review requirement after release upgrades or service changes.
Avoid a universal hardening recipe #
The strongest-looking policy is not necessarily the correct policy. MLS, Biba, and LOMAC require information-flow models that ordinary workstations and mixed-purpose servers may not possess. Enabling them without classification ownership can convert routine administration into unexplained denials and encourage unsafe exemptions.
Prefer the least policy that makes the stated denial reliable. If the denial cannot be described and tested, the MAC configuration is not ready to implement.