7

Example:

# show starting permissions
% stat -c '%04a' ~/testdir
0700

# change permissions to 2700
% chmod 2700 ~/testdir

# check
% stat -c '%04a' ~/testdir
2700

# so far so good...

# now, change permissions back to 0700
% chmod 0700 ~/testdir

# check
% stat -c '%04a' ~/testdir
2700

# huh???

# try a different tack
% chmod g-w ~/testdir
% stat -c '%04a' ~/testdir
0700

Bug or feature?

Why does chmod 0700 ~/testdir fail to change the permissions from 2700 to 0700?

I've observed the same behavior in several different filesystems. E.g., in the latest one, the relevant line of mount's output is

/dev/sda5 on / type ext4 (rw,relatime,errors=remount-ro,data=ordered)

Also, FWIW

% stat -c '%04a' ~/
0755
2
  • Are you seeing any permission denied messages? This would be the normal behavior in situations where you may have selinux running. Nov 9, 2017 at 15:49
  • @RamanSailopal: what I show in the question is verbatim output. (IOW: no error messages at all.)
    – kjo
    Nov 9, 2017 at 16:02

3 Answers 3

20

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).

4
  • Thanks! Unfortunately, the documentation doesn't make the behavior look any less capricious... Would you happen to know why GNU chmod has this particular policy? IOW, is there any justification for it beyond "POSIX doesn't prohibit it"? Does it provide any benefit?
    – kjo
    Nov 9, 2017 at 16:00
  • 1
    I tracked down the rationale, see my update. Nov 9, 2017 at 16:21
  • I agree this is pretty darn capricious and I feel very much like dyking that behavior out.
    – Joshua
    Nov 9, 2017 at 17:29
  • 1
    Heh. As someone who frequently uses setuid/setgid directories in situations where their unintended removal would be unfortunate (would prevent services from being able to access data directories they need read access to, granted via group ownership), I'm happy about this. J. Random User is likely to have scripts and habits that refer to "755" or "550" or whatever and not realize that they need to preserve setuid/setgid when mucking around in directories that are intended to be accessible to other accounts via group permissions. Nov 9, 2017 at 20:59
0

Try this:

chmod 000700 ~/testdir

-2

show starting permissions

% stat -c '%04a' ~/testdir 0700

==> OK!

change permissions to 2700

% chmod 2700 ~/testdir

==> Note that you are setting Group ID!!!

check

% stat -c '%04a' ~/testdir 2700

==> OK!

so far so good...

now, change permissions back to 0700

% chmod 0700 ~/testdir

==> Again, pls note that you are remove the flag restricted deletion or sticky (not group id).

check

% stat -c '%04a' ~/testdir 2700

huh???

try a different tack

% chmod g-w ~/testdir % stat -c '%04a' ~/testdir 0700

=========================================================== Lastthing, you can use this command to get success:

chmod 000700 ~/testdir
2
  • 1
    I don't think a five minute video is necessary or appropriate here
    – Darren H
    Nov 9, 2017 at 21:31
  • Sorry, it is not my intent. That five minute's be caused by my kid issue. I'll fix it later.
    – Tech. Pro
    Nov 10, 2017 at 2:25

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .