java-native-access/jna · error · IllegalArgumentException

SECURITY_DESCRIPTOR_RELATIVE does not contain SACL

Error message

SECURITY_DESCRIPTOR_RELATIVE does not contain SACL

What it means

When setSACL is requested but the SECURITY_DESCRIPTOR_RELATIVE has no system ACL (sacl is null), Advapi32Util throws IllegalArgumentException. The library refuses to apply a null SACL via the descriptor components API.

Source

Thrown at contrib/platform/src/com/sun/jna/platform/win32/Advapi32Util.java:2899

        if (setGroup) {
            if (psidGroup == null)
                throw new IllegalArgumentException("SECURITY_DESCRIPTOR_RELATIVE does not contain group");
            if (!Advapi32.INSTANCE.IsValidSid(psidGroup))
                throw new IllegalArgumentException("Group PSID is invalid");
            infoType |= GROUP_SECURITY_INFORMATION;
        }

        if (setDACL) {
            if (dacl == null)
                throw new IllegalArgumentException("SECURITY_DESCRIPTOR_RELATIVE does not contain DACL");
            if (!Advapi32.INSTANCE.IsValidAcl(dacl.getPointer()))
                throw new IllegalArgumentException("DACL is invalid");
            infoType |= DACL_SECURITY_INFORMATION;
        }

        if (setSACL) {
            if (sacl == null)
                throw new IllegalArgumentException("SECURITY_DESCRIPTOR_RELATIVE does not contain SACL");
            if (!Advapi32.INSTANCE.IsValidAcl(sacl.getPointer()))
                throw new IllegalArgumentException("SACL is invalid");
            infoType |= SACL_SECURITY_INFORMATION;
        }

        /*
         * Control bits SE_DACL_PROTECTED/SE_SACL_PROTECTED indicate the *ACL is protected. The *ACL_SECURITY_INFORMATION flags
         * are meta flags for SetNamedSecurityInfo and are not stored in the SD.  If either *ACLProtectedStatus is set,
         * get the current status from the securityDescriptor and apply as such, otherwise the ACL remains at its default.
        */
        if (setDACLProtectedStatus) {
            if ((securityDescriptor.Control & SE_DACL_PROTECTED) != 0) {
                infoType |= PROTECTED_DACL_SECURITY_INFORMATION;
            }
            else if ((securityDescriptor.Control & SE_DACL_PROTECTED) == 0) {
                infoType |= UNPROTECTED_DACL_SECURITY_INFORMATION;
            }
        }

View on GitHub (pinned to d036ad9781)

Solutions

  1. Check securityDescriptor.getSystemACL() for null and pass setSACL=false when absent.
  2. Read the SACL with sufficient privileges (SE_SECURITY_NAME privilege enabled) via Advapi32.GetSecurityDescriptorSacl.
  3. Drop SACL_SECURITY_INFORMATION from the requested components if audit policy is not required.
  4. Build and attach a valid SACL to the descriptor before the call.

Example fix

// before
Advapi32Util.setSecurityDescriptorComponents(sd, true, true, true, true, false, false);
// after
Advapi32Util.setSecurityDescriptorComponents(sd, true, true, true, sd.getSystemACL() != null, false, false);
Defensive patterns

Strategy: validation

Validate before calling

if (securityDescriptor.getSystemACL() == null) {
    throw new IllegalStateException("Descriptor has no SACL; omit SACL component");
}

Type guard

boolean hasSACL(SECURITY_DESCRIPTOR_RELATIVE sd) {
    return sd != null && sd.getSystemACL() != null;
}

Try / catch

try {
    Advapi32Util.setSecurityDescriptorComponents(sd, setOwner, setGroup, setDACL, setSACL, false, false);
} catch (IllegalArgumentException e) {
    log.warn("SACL missing/invalid: " + e.getMessage());
}

Prevention

When it happens

Trigger: Calling with setSACL=true on a descriptor without SE_SACL_PRESENT control bit or whose SACL was never parsed; also commonly hit when the caller lacked READ_CONTROL/access-system-security rights so the source SACL came back empty.

Common situations: Copying audit settings from an object where SACL reading was silently skipped due to privileges; descriptors with DACL but no SACL; manually built descriptors with audit flags unset.

Related errors


AI-assisted analysis of java-native-access/jna@d036ad9781 (2026-09-12). Data as JSON: /api/errors/15a4371391e04125. Report an issue: GitHub.