Inherited access control entries are captured when the child object is created

In the discussion of how to change permissions as fast as Explorer does it, it appears that it was not clear to people how inherited access control entries work, so there were a lot of suggestions based on faulty mental models. So let me explain.

Inherited permissions on an object are established when the object is created. Once the object has been created, you can change the permissions of the parent and it won't have any effect unless you explicitly ask for the inheritable properties to be re-propagated to child objects. (You may recall that the CREATOR_OWNER SID works in a similar way.)

Let's say this again. Each file has a security descriptor. To determine whether you can access a file, the only thing that is consulted is the security descriptor on the file being accessed. The security descriptors on the parent folders do not enter the picture, except possibly to determine whether traversal is allowed.¹

Now, let's talk about these alternate theories from the comments.

"I suspect the false [second parameter to Object­Security.Set­Access­Rule­Protection] is the problem."

The security descriptor on a file can be marked as "protected". This means "If somebody changes the security attributes on a parent folder and tries to propagate inheritable attributes to children, do not apply the inheritable attributes to me." You can think of it as an "renounce inheritance" bit on a security descriptor. If you set the bit, then you're saying, "I know my grandmother left me a collection of antique creamers shaped like animals, but I don't want them."

The Object­Security.Set­Access­Rule­Protection method lets you set or clear the "renounce inheritance" bit, and if you choose to renounce the inheritance, you can set the second parameter to false to say that you want to renounce the access control entries that you already inherited. (Say, because they remind you of grandma's unpleasant smell.)

While that last parameter is interesting, it has nothing to do with the problem at hand, since that bit controls the security attributes of a single file and does not perform any propagation.

"Does it take Explorer two minutes to change parent directory permissions when the ACL specifies that the changes are supposed to be inherited from the parent directory? That would surprise me. (Does inheritance work by altering every descendant rather than the permission check testing ancestors?)"

When you change the security attributes of a parent folder, you are typically asked whether you want to propagate inheritable attributes to children. If you say Yes, then the security attributes of the children are overwritten with values that are consistent with the security attributes of the parent. It is this step (rewriting security descriptors of all children) that takes a long time.

(The Advanced Security Settings dialog assumes you always say Yes, becaus it goes hunting up the parent tree looking for the source of your inheritable ACEs, and it it doesn't find one, it just shrugs.)

Walking up the directory tree is a tricky proposition in practice for a variety of reasons. First of all, the existence of hard links means that a file can have multiple parent directories. Do you have to walk up all of them? Or only the one that was used to open the file? (In which case, it means that the effective security attributes of a file can vary depending on which path you use to open it.) And what if you open the file by using its GUID instead of a file name or path? What is the "parent directory"?

Windows takes the position that the security descriptor is an attribute of the object itself, not its containers. The container can influence the default security descriptor at the time a child object is created, but once that's done, the child object can exercise its own free will and make its own choices.

Bonus chatter: In practice, you may have a lot of files, but you almost never have a lot of unique security descriptors. For example, all the files in a directory typically have the same security descriptor, and a directory typically has the same security descriptor as its parent. Therefore, NTFS keeps all the security descriptors in a single table, and all the files with the same security descriptor share an entry in the table.

¹ Security checks on traversal are normally disabled, so by default, you can access anything whose security descriptor grants you access, as long as you know its path. You can take advantage of this: Create a directory, let's call it Parent, that denies List Folder Contents to everyone. Inside this directory, create subdirectories that grant access only to certain people, and give the names of those subdirectories to those people. For example, you might grant Bob read access to the Manhattan subdirectory. Bob can cd into Parent\Manhattan to see what's in it, but if Bob tries to cd into Parent and do a dir, he sees nothing.

Comments (8)
  1. MarcK4096 says:

    I don’t think I’ve had Explorer ask me about changing down-level permissions unless I check the “Replace all child object permission entries with inheritable permission entries from this object” box. It’s been my experience that Explorer does try to update down-level inherited permissions, which I like. I imagine this is what leads people to the incorrect conclusion that inherited permissions are more than they are and then get confused when they discover otherwise. I know older versions of Explorer would not update inherited permissions when moving files within the same volume and this would bite users. We’d get support calls of the type “I moved files from my home folder into the shared folder and no one can access them” and we had to tell them “Don’t move the files. Copy, then delete the originals.” I was happy when we upgraded to Windows 7 and this was no longer required.

  2. Medinoc says:

    My understanding of the checkbox was that if checked, Explorer would overwrite ALL permissions from the descendant objects, while if not checked, only those with the INHERITED_ACE flag would be updated.

    Do you mean that there is no such behavior, only “overwrite all” and “don’t touch child elements”?

  3. DWalker says:

    @MarcK: “I don’t think I’ve had Explorer ask me about changing down-level permissions unless I check the “Replace all child object permission entries with inheritable permission entries from this object” box. It’s been my experience that Explorer does try to update down-level inherited permissions, which I like.”

    Yes, I think that’s what Raymond is saying, and what happens. When you check the “Replace…” box, Explorer asks “do you really want to do what you just asked to do?” (kind of redundantly) and then it does the replacement of the permissions on the children.

  4. Myria says:

    Why does SeChangeNotifyPrivilege incorporate two separate privileges–the ability to be notified when files/directories change, and traverse checking bypassing? It would’ve been nice if disabling traverse checking wouldn’t mess up other stuff, like Explorer refreshing file lists.

  5. Neil says:

    What I don’t understand is why Explorer insists on “updating” down-level permissions when I set a permission of type “This folder only”.

  6. Neil says:

    I feel sure there could be a way to optimise shared descriptors so that a leaf subtree (i.e. a subtree where all the descriptors are shared) could share a descriptor that is unique to the subtree, meaning that you could change the permissions on the subtree in one fell swoop just by updating that descriptor.

  7. paul page says:

    This seems like a good spot for some sort of “renounce your privilege” joke.

  8. Medinoc says:

    Speaking of file access rights, what does FILE_READ_EA *actually* mean? I have tried, and failed, to find a Windows API function that would be documented to need FILE_READ_EA access…

Comments are closed.

Skip to main content