Assuming you’re using GNU chmod
, this is documented in the manpage:
chmod
preserves a directory's set-user-ID and set-group-ID bits unless you explicitly specify otherwise.
You can set or clear the bits with symbolic modes like u+s
and g-s
, and you can set (but not clear) the
bits with a numeric mode.
This is allowed in POSIX:
For each bit set in the octal number, the corresponding file permission bit shown in the following table shall be set; all other file permission bits shall be cleared. For regular files, for each bit set in the octal number corresponding to the set-user-ID-on-execution or the set-group-ID-on-execution, bits shown in the following table shall be set; if these bits are not set in the octal number, they are cleared. For other file types, it is implementation-defined whether or not requests to set or clear the set-user-ID-on-execution or set-group-ID-on-execution bits are honored.
The reasoning for the behaviour in GNU chmod
is given in the release notes for coreutils
6.0:
chmod
, install
, and mkdir
now preserve a directory's set-user-ID and
set-group-ID bits unless you explicitly request otherwise. E.g.,
chmod 755 DIR
and chmod u=rwx,go=rx DIR
now preserve DIR
's
set-user-ID and set-group-ID bits instead of clearing them, and
similarly for mkdir -m 755 DIR
and mkdir -m u=rwx,go=rx DIR
. To
clear the bits, mention them explicitly in a symbolic mode, e.g.,
mkdir -m u=rwx,go=rx,-s DIR
. To set them, mention them explicitly
in either a symbolic or a numeric mode, e.g., mkdir -m 2755 DIR
,
mkdir -m u=rwx,go=rx,g+s DIR
. This change is for convenience on
systems where these bits inherit from parents. Unfortunately other
operating systems are not consistent here, and portable scripts
cannot assume the bits are set, cleared, or preserved, even when the
bits are explicitly mentioned. For example, OpenBSD 3.9 mkdir -m 777 D
preserves D
's setgid bit but chmod 777 D
clears it.
Conversely, Solaris 10 mkdir -m 777 D
, mkdir -m g-s D
, and
chmod 0777 D
all preserve D
's setgid bit, and you must use
something like chmod g-s D
to clear it.
There’s more on the topic in #8391, including the further rationale that the leading 0 is ambiguous (it could indicate either cleared bits, or an octal value, in the user’s mind). The coreutils
manual also has a dedicated section, Directories and the Set-User-ID and Set-Group-ID Bits; this reveals that there are GNU extensions to allow clearing the bits in question:
chmod =700 ~/testdir
chmod 00700 ~/testdir
both clear the bits (but are non-portable).