A shared directory carries an ACL granting a named group write access, yet files newly created inside it do not get that access. How do POSIX default ACLs work, and what determines the permissions of a file created in such a directory?
answer
- directories can hold two lists
- a template, not a rule
- stamped once at creation time
- umask steps aside
- existing files were never touched
basics
~20 sAn ordinary ACL controls access to the directory itself and is not inherited. Inheritance requires a separate default ACL, set with setfacl -d, which acts as a template copied onto newly created files and subdirectories. When one exists, the process umask is not applied.
solid answer
~50 sA directory can carry two ACLs. The **access ACL** decides who may act on the directory itself, and it never propagates. The **default ACL**, set with `setfacl -d -m g:devs:rwx dir` and shown by `getfacl` on `default:` lines, is pure inheritance metadata: the kernel copies it onto every file and subdirectory created inside. A new subdirectory receives it as both its own access ACL and its own default ACL, so inheritance continues downward; a new file receives it as an access ACL only. Crucially, when a default ACL is present the process umask is ignored — instead the inherited owner, mask and other entries are reduced by the mode the creating program requested (typically 0666 for files, 0777 for directories). And a default ACL changes nothing about files that already exist, so retrofitting a directory takes two operations: `setfacl -R -m ...` for the existing tree and `setfacl -d -m ...` for what comes next.
code
bash · 7 linesmkdir -p /tmp/shared
setfacl -m g:adm:rwx /tmp/shared # access ACL: use the directory
setfacl -d -m g:adm:rwx /tmp/shared # default ACL: template for new files
getfacl /tmp/shared # note the default: lines
touch /tmp/shared/new.txt
getfacl /tmp/shared/new.txt # group:adm:rwx inherited, x dropped
setfacl -k /tmp/shared # stop inheriting, keep current accessgo deeper
Know that inheritance needs a separate default ACL created with setfacl -d, that getfacl shows it on default: lines, and that it affects only files created after you set it.
Explain that the default ACL is a template copied at creation time — as an access ACL for files, as both access and default for subdirectories — and that the umask is bypassed while the creating program's requested mode still reduces the result.
Anticipate the gaps: files moved rather than created, atomic write-and-rename patterns landing files elsewhere, and later recursive chmods clamping the inherited entries through the mask. Retrofit with both a recursive -m and a recursive -d -m.
Decide whether shared-directory behaviour is guaranteed by default ACLs, by group ownership conventions, or by the applications themselves, and make that choice explicit — a scheme depending on every writer's personal umask is the one that fails silently at scale.
## Two ACLs on one directory Regular files have one ACL. Directories may have two, and conflating them is the usual source of "my ACL isn't working": - The **access ACL** answers "who may read, write or traverse *this directory*". It behaves exactly like a file's ACL and has no effect on anything created inside. - The **default ACL** answers "what ACL should new entries in this directory start with". It grants no access to anyone by itself — it is a template. `getfacl` prints them together, prefixing the template with `default:`: ``` $ getfacl /srv/shared # file: srv/shared # owner: root # group: staff user::rwx group::r-x other::r-x default:user::rwx default:group::r-x default:group:devs:rwx default:mask::rwx default:other::r-x ``` You set default entries with `setfacl -d -m ...`, which is exactly equivalent to prefixing the entry with `d:`: ``` $ setfacl -d -m g:devs:rwx /srv/shared $ setfacl -m d:g:devs:rwx /srv/shared # identical ``` A default ACL must be complete: if you add one named entry, `setfacl` fills in `default:user::`, `default:group::`, `default:other::` and `default:mask::` for you, seeding them from the directory's own access ACL. ## What happens at file creation When a process calls `open(..., O_CREAT, mode)` or `mkdir(path, mode)` in a directory that has a default ACL, the kernel does this: 1. Copies the parent's default ACL onto the new object as its **access ACL**. 2. If the new object is a **directory**, also copies the default ACL onto it as its own **default ACL**, so inheritance keeps flowing down the tree. 3. Reduces the three mode-bearing entries — `user::`, the group class (i.e. the `mask` when the ACL is extended, otherwise `group::`), and `other::` — by the corresponding triads of the `mode` argument the program passed. And the point candidates most often miss: **the umask is not consulted at all**. The umask is the fallback rule for directories with no default ACL. Once a default ACL exists, the administrator's template plus the creating program's requested mode fully determine the outcome. That is what makes default ACLs usable for shared directories — you are no longer at the mercy of each user's personal `umask` setting. Because most programs request `0666` for files and `0777` for directories, the practical effect is that inherited named entries survive intact while the executable bit is dropped from ordinary files, which is what you want. ## Retrofitting an existing directory This is the second half of the interview answer. A default ACL is applied at creation time only — it is not a live rule evaluated on access, and it does not reach backwards. A directory that already contains a thousand files needs two commands: ``` $ setfacl -R -m g:devs:rwX /srv/shared # existing files and directories $ setfacl -R -d -m g:devs:rwx /srv/shared # the template for future ones ``` (`-R` recurses; `-d` selects the default ACL. Note that `-R` on its own does *not* imply `-d`, and `-d` on its own does *not* touch existing content — that asymmetry is the whole reason people believe inheritance is broken.) To remove inheritance without disturbing current access, use `setfacl -k dir`, which deletes the default ACL only. `setfacl -b dir` removes the extended entries of both. ## Where it goes wrong in production - **A file moved in, not created in.** `mv` across a rename within the same filesystem preserves the file's existing ACL; the default ACL is applied only on *creation*. Copying with a tool that creates a new file (`cp` without ACL preservation) does inherit the default. Two paths that look identical to a user produce different ACLs. - **A process that writes atomically.** Editors and daemons that write to a temporary file and `rename()` it into place produce a file that inherited from whichever directory the temporary was created in. - **A later chmod.** Because the group-class mode bits address the mask on an extended ACL, a `chmod` on inherited files clamps the inherited named entries just as it does anywhere else. - **Confusing the two ACLs.** Granting `g:devs:rwx` on the directory itself lets the group create and delete entries in it, but every file they create still lands with only their personal default rights. Both halves are usually needed. ## The mental model An access ACL is a rule the kernel evaluates on every access. A default ACL is a stamp applied exactly once, at creation. If you keep that distinction, the behaviour of a shared directory becomes predictable: `getfacl` on the parent tells you what new files will look like, and `getfacl` on the file tells you what it actually got.
- What does a new subdirectory inherit that a new regular file does not?A new subdirectory receives the parent's default ACL twice: once as its own access ACL, deciding who may use it, and once as its own default ACL, so the template continues to propagate to anything created deeper. A regular file gets the template only as an access ACL, because a file has nothing to pass on.
- How do you remove inheritance from a directory without changing who can access the directory today?`setfacl -k dir` deletes only the default ACL, leaving the access ACL untouched, so current permissions on the directory are unchanged while newly created files stop inheriting. By contrast `setfacl -b dir` strips the extended entries from both, which does change who can reach the directory.
- A file was moved into the shared directory instead of created there and did not pick up the ACL. Why?The default ACL is applied by the kernel at creation time only — during `open(O_CREAT)` or `mkdir`. A `rename()` within the same filesystem moves the existing inode, which keeps the ACL it was created with. Copying it with a tool that creates a fresh file, or re-applying with `setfacl -R -m`, is what fixes such a file.
saying these in an interview costs you the question
- Expecting a plain ACL on a directory to be inherited by its files
- Thinking the default ACL retroactively fixes existing files
- Believing the umask still applies inside a default-ACL directory
- Assuming -R also sets the default ACL
- Treating the default ACL as a live access rule on the directory