Managing file security

Use sd to inspect selected file policy and make bounded changes to its owner, access rules, audit rules or integrity label. Start with one known path and one intended change. A permission failure is a reason to diagnose the denied operation, not to replace the descriptor or grant full control.

1. Inspect the path and current policy #

These commands only inspect the example file; replace ./report.txt with the intended path:

sd show ./report.txt --all
sd show ./report.txt --sddl
sd check ./report.txt read --explain

Record the owner, group, displayed DACL entries and their order, inheritance flags, and label information. Keep the output as a before-change record. sd show queries owner, group, DACL and the label subset, not the full SACL; --all and --sddl do not add audit entries. Its output is not a complete descriptor backup or a tested rollback input. Human and JSON summaries also omit some ACE payload details. If the change requires inspecting audit policy or other omitted data, resolve that verification gap before writing.

A named symlink follows its target by default. To inspect or change the link itself, use the documented --no-follow-symlinks (-P) flag consistently. Confirm which object you mean before writing.

sd check rehearses an access decision without performing the operation. Its result is evidence for the selected token and descriptor; it does not prove that an application's original operation will work. If inspection fails or leaves necessary policy unknown, resolve that visibility gap before changing it.

2. State the intended change #

Choose the smallest component and scope that express the policy. The command reference has the complete syntax.

Intended resultDocumented command familyWhat to check first
Add an allow or deny ACEsd allow, sd denyPrincipal, exact rights, ACE order and inheritance flags. --replace removes existing rules for that principal and kind before adding.
Remove a principal's DACL rulessd removeIt removes every allow and deny rule for each named principal. Removing a deny can increase access.
Change owner or primary groupsd owner, sd groupWRITE_OWNER and the new-owner SID restrictions below; ownership does not grant file-data access.
Change audit rulessd audit, sd unauditSACL authority. unaudit removes every SACL rule for the named principals.
Change an integrity labelsd integrityIntended mandatory policy, WRITE_OWNER and the caller's integrity constraint. Do not lower a label merely to make a denial disappear.
Change inheritance or refresh childrensd inherit, sd reset, sd propagateWhether explicit child rules or protection should survive; inspect the affected descendants first.
Replace a reviewed descriptor or selected componentssd setThe full replacement and its recovery path. --components selects which owner/group/DACL/SACL parts to write; do not use a whole-descriptor replacement for a one-ACE change.

sd reset drops explicit rules and protection and rebuilds the DACL from the parent. sd remove --allow-empty permits a present-but-empty DACL, which grants no rights through its ACE list. An absent DACL has very different, permissive semantics. Neither is a routine way to fix an unexplained denial; see DACL evaluation.

Inheritance is stored on the child. Changing the parent's rules does not update existing children automatically; propagation is a separate, intentional operation.

3. Make the bounded change #

For example, if the approved policy is to add read access for the identity running sd on this one file:

sd allow ./report.txt @self:read

@self means the current caller's user SID, not the file owner and not the user of another application. Choose the intended principal explicitly. This adds an ACE; it does not remove earlier denies or bypass mandatory policy. A later allow cannot change a right already decided by an earlier matching ACE.

Run only the command matching the intended change. Avoid concurrent edits to the same descriptor. With an existing valid descriptor, component selection preserves unselected fields, but a read/edit/write sequence does not reserve the policy against another writer. The kernel storage contract describes last-writer-wins behavior and a cache/xattr publication window, not an end-to-end transaction.

4. Verify policy and the original operation #

After the change, inspect the same object again and compare it with the before-change record:

sd show ./report.txt --all
sd check ./report.txt read --explain

Check the intended principal, rights and unrelated policy within the returned view. Matching sd show output cannot verify audit ACEs, omitted payloads or complete descriptor equality. Audit-policy changes need a separately established full-SACL inspection path; this guide does not supply one. Then retry the original operation with its actual caller. Check both access that should succeed and access the policy should still refuse, where it is safe to do so.

Existing file handles keep the rights granted when they were opened. A DACL edit is not a revocation of those handles; use a fresh open to test future access. See The handle model.

A nonzero sd status can mean a failed operation, an unreachable path, or a denied sd check; read the diagnostic. After recursive work, inspect the reported failures and representative descendants rather than treating the whole tree as changed. If the result differs from the intention, stop widening the change and use the denial guide.

Why the xattr layer is denied #

Do not edit the backing security.peios.sd or system.ntfs_security xattr. Raw reads, writes and removal are denied. Use sd, or the component-aware SDK interface when writing a program; this keeps validation and the separate SACL gate intact. See File Descriptor Storage.

Rights and constraints #

ComponentReading needsChanging needs
Owner or primary groupREAD_CONTROLWRITE_OWNER; new-owner SID validation also applies.
DACLREAD_CONTROLWRITE_DAC
SACLACCESS_SYSTEM_SECURITYACCESS_SYSTEM_SECURITY, gated by SeSecurityPrivilege.
Integrity label onlyREAD_CONTROLWRITE_OWNER; without SeRelabelPrivilege, the new label cannot exceed the caller's integrity.

Requests for several components must pass every required check. MIC, PIP and other access layers still apply; owner implicit rights are not an exception to all of them.

Without SeRestorePrivilege, a new owner must be the caller's user SID or a token group carrying SE_GROUP_OWNER. Being the owner or an administrator does not itself prove the operation can pass WRITE_OWNER. See Changing ownership.

A label-only change preserves non-label SACL entries; a full SACL write replaces the whole SACL. The integrity constraint applies through either path: a label above the caller's integrity needs enabled SeRelabelPrivilege, even for a full SACL write. SeSecurityPrivilege or SeRestorePrivilege alone does not remove that constraint. Existing mandatory resource attributes cannot be removed or modified without SeTcbPrivilege.

For programs, the SDK guide covers kacs_get_sd, kacs_set_sd, mutually exclusive SACL/label requests, the 65,535-byte validation limit and component merging. Operator changes should use the component command rather than construct a binary descriptor.

What about file mode (the POSIX rwx bits)? #

chmod changes mode metadata, not the DACL. FACS does not use the ordinary rwx bits to authorize access; the execute bit still matters as an exec prerequisite. Use sd to change the access policy.

  • fchmod() needs WRITE_DAC in the fd's granted mask; otherwise it fails with EACCES (EBADF for an O_PATH fd). Legacy opens request this as a compatibility right.
  • chmod() runs a fresh check for WRITE_DAC.
  • Neither operation changes the descriptor.

See Use-Time Checks for the syscall behavior.

Errors #

If a change is denied, check the required component right, the caller, owner-SID constraints, integrity and other mandatory policy before retrying. A read-only mount can refuse a write even if the descriptor permits it. Do not infer that a failed multi-object run left every object unchanged.

The SDK error reference distinguishes access, validation, buffer and path errors for programs. For an operator, keep sd's diagnostic and follow Debugging a denial.

See also #

Edit this page