Skip to content
FreeBSDHow-To Published Updated 7 min readViews unavailable

FreeBSD chflags: Immutable Files, Targeted Recovery, and Securelevel Boundaries

Diagnose FreeBSD file flags independently of permissions, test owner-level immutable protection, and recover narrowly without clearing unrelated policy.

An administrator can have the correct ownership and mode bits yet still receive “Operation not permitted” when updating a FreeBSD file. File flags are one possible reason. They add policy beyond ordinary Unix permissions, and their user-level and system-level forms have different recovery rules. Treating every such failure as a reason to run a recursive permission reset can remove deliberate protection while leaving the actual cause misunderstood.

This guide uses the FreeBSD 15.0 chflags(1), chflags(2), and security(7) source-tree manuals. Filesystem support is explicitly implementation-dependent. The examples are for a disposable file owned by the operator on a FreeBSD filesystem supporting the selected flags, not for macOS protected files, a live system root, or a remote share whose flag behavior has not been established.

Separate flags from other access controls

Start with the exact failed operation, target path, calling identity, and mount. Read permission, write permission, renaming, and deletion are not identical requests. A read-only mount, an ACL, a parent-directory policy, or an unsupported filesystem feature can produce an operational symptom that resembles immutable-file protection.

Use ls -lo to inspect flags alongside the usual ownership and mode information. Inspect the relevant containing directories as well as the file. A directory entry operation depends on the directory context; checking only the file’s mode is not a complete diagnosis. Preserve the original command’s diagnostic and exit status rather than replacing it with a different operation that happens to succeed.

Record filesystem type and mount options before changing anything. A FreeBSD pathname can refer to UFS, ZFS, a network filesystem, or a compatibility filesystem. The system-call manual explicitly warns applications to account for support or lack of support of flags. A successful workflow on one filesystem does not certify another mount with the same-looking pathname.

Choose the smallest useful flag

The user immutable flag, uchg, corresponds to UF_IMMUTABLE. The system immutable flag, schg, corresponds to SF_IMMUTABLE. Both express protection against changing a file, but the authority required to manipulate them differs. The owner or superuser can set or clear the user flag, while system flags require superuser authority and interact with securelevel.

Append-only flags express a different contract: the file may only be appended to. They do not substitute for a reviewed logging pipeline, a remote audit copy, or a retention system. Likewise, the no-unlink flags constrain renaming and deletion rather than expressing a complete content-integrity policy. Select a flag based on the operation that should be restricted, not on whichever keyword sounds strongest.

Immutable protection is not encryption or a backup. It does not prove that the original content was correct, protect it from every privileged/offline adversary, or provide a previous revision after hardware failure. Store an independent digest and recoverable copy when those are requirements. A file can be protected against local modification and still contain an erroneous configuration.

Test owner-level protection in isolation

The following illustrative FreeBSD shell fixture creates a private directory, writes one disposable file, sets its user immutable flag, and verifies that an append is rejected. It then clears only that flag and verifies the content can be updated again. Run it on an approved scratch filesystem as an ordinary user, not against a service configuration.

set -eu
umask 077
work=$(mktemp -d /tmp/chflags-contract.XXXXXX)
file="$work/probe.txt"

printf '%s\n' baseline > "$file"
chflags uchg "$file"
ls -lo "$file"

if (printf '%s\n' unexpected >> "$file") 2> "$work/blocked-write.log"; then
    printf '%s\n' 'ERROR: append unexpectedly succeeded' >&2
    exit 1
fi

chflags nouchg "$file"
printf '%s\n' approved >> "$file"
printf '%s\n' baseline approved > "$work/expected.txt"
cmp "$file" "$work/expected.txt"
ls -lo "$file"
printf 'Scratch evidence retained at %s\n' "$work"

The directory is deliberately retained for inspection. If the first flag-setting command fails, set -e stops the fixture before the negative test; that failure must not be reinterpreted as successful protection. If the write succeeds unexpectedly, inspect filesystem support and the observed flags. No native FreeBSD execution is claimed for this example during authoring.

Use nouchg to remove the user immutable flag. A numeric argument of zero clears all file flags. It is therefore not an equivalent recovery command when other policy bits matter. An incident procedure should identify exactly which flag is obstructing the authorized change and preserve the rest.

Recovery begins with identity and evidence

For a real blocked update, capture the path, flags, ownership, checksum, and relevant service state before editing. Confirm that the operator is changing the intended object, not a symlink target, similarly named file, or different mount. If there is evidence of unauthorized modification, preserve it and use the incident process rather than immediately removing the protection.

When the authorized change requires removing uchg, clear that one flag on the verified object, perform the bounded update, validate the resulting content, and restore the intended flag. Coordinate with the application so it does not write a competing version during the maintenance window. Restoring protection does not make an invalid update correct; service behavior and content validation remain separate gates.

Avoid using chflags -f in verification scripts. The manual states that this option suppresses both diagnostics and the failure contribution to exit status. A command that appears quiet and successful can therefore hide the exact failure the script is meant to detect. Prefer checked commands and explicit before/after inspection.

Securelevel changes the system-flag recovery path

System immutable, system append-only, and system no-unlink flags have stronger administrative constraints. The system-call manual describes the interaction with securelevel; security(7) explains that secure mode prevents clearing the system immutable and append-only flags. A root shell is not sufficient evidence that clearing them will be permitted in the current state.

Read kern.securelevel before planning recovery. Do not respond to an individual file problem by attempting to lower a live host’s security level. The documented security model does not permit an ordinary privileged process to freely lower it after raising it. Recovery may require a controlled boot or maintenance environment with the appropriate state and authorization, plus console access and a tested restoration plan.

This article intentionally provides no whole-host securelevel change or recursive schg recipe. Those changes can interfere with upgrades, module management, and other system operations. Setting system flags broadly without verifying the recovery path can turn routine maintenance into an outage. Test the proposed policy and its removal on a disposable host before applying it to critical startup files.

-R applies changes recursively. -H, -L, and -P influence traversal of symbolic links in that recursive context, while -h requests modification of a symbolic link itself. The manual also documents a nonrecursive default case where a symbolic-link operation can succeed without changing flags. Success status alone is consequently not proof that the expected object was modified.

Do not use a wildcard such as .* with a broad recursive flag change. The manual specifically warns about accidentally including parent-directory entries. When a hierarchy really needs maintenance, inventory it, choose an explicit traversal policy, consider mount boundaries, and inspect the resulting flags. A narrow single-file recovery should remain a narrow single-file operation.

Backup and restore workflows must also account for flag-aware tools and destination support. Verify protected-file recovery using the exact toolchain and filesystem rather than assuming preservation because content bytes match. Retain a manifest of the intended metadata and restore it as part of a tested recovery sequence.

Acceptance criteria

A working policy demonstrates the intended denial, an authorized removal path, successful validated modification, and restoration of the selected protection without erasing unrelated flags. It also records the filesystem, securelevel, tool version, and operator identity. That evidence is stronger than a one-time chflags success.

If a filesystem or recovery environment cannot satisfy the contract, choose a different protection mechanism or narrow the scope. File flags are useful when they are deliberately operated and tested. They become hazardous when applied as an unexplained fix to every permission error.

Related:

Sources:

Comments