1

I am trying to create a a directory with permissions 02770, so that the resultant permissions would be drwxrws---

When I run the below commands I get the expected behavior

rsam.svtest2.serendipity> (/home/svtest2)
$ mkdir abc


rsam.svtest2.serendipity> (/home/svtest2)
$ ls -lrt
drwxrwxr-x  2 svtest2 users    6 Apr 18 10:57 abc

rsam.svtest2.serendipity> (/home/svtest2)
$ chmod 02770 abc

rsam.svtest2.serendipity> (/home/svtest2)
$ ls -lrt
drwxrws---  2 svtest2 users    6 Apr 18 10:57 abc

UPDATE#1 Following from above, after running mkdir and chmod on a directory, when I run chown the SGID bit gets cleared off.

rsam.svtest2.serendipity> (/home/svtest2)
$ chown svtest2:users abc



rsam.svtest2.serendipity> (/home/svtest2)
$ ls -lrt
drwxrwx---  2 svtest2 users    6 Apr 18 10:57 abc

From the chown documentation,

Only a privileged process (Linux: one with the CAP_CHOWN capability) may change the owner of a file. The owner of a file may change the group of the file to any group of which that owner is a member. A privileged process (Linux: with CAP_CHOWN) may change the group arbitrarily.

The problem is that my user svtest does not have CAP_CHOWN capability. Now the question boils down to - How to I get the user to have CAP_CHOWN capability?

It looks like there is some instruction here - SO - setting CAP_CHOWN but I am yet to try it out.

However, when I run below C++ code(part of tuxedo server)

// Check if the directory exists and if not creates the directory
// with the given permissions.
struct stat st;
int lreturn_code = stat(l_string, &st);



if (lreturn_code != 0 &&
    (mkdir(l_string, lpermission) != 0 ||
     chmod(l_string, lpermission) != 0)) {
     ....
     ....
     }
     ....
     ....
// Convert group name to group id into lgroup
        if (chown(l_string, -1, lgroup) != 0) {
            // System error.
        }

The directory is created as below:

$ ls -l|grep DirLevel1
drwxrwx--- 2 svtest2 users         6 Apr 18 11:14 DirLevel1

Notice that the SGUID bit is not set as against when the commands were run directly as mentioned above.

Excerpt from strace for the operation:

5864  stat("/home/svtest2/data/server/log/DirLevel1/", 0x7ffd235f29f0) = -1       ENOENT (No such file or directory)
5864  mkdir("/home/svtest2/data/server/log/DirLevel1/", 02770) = 0
5864  chmod("/home/svtest2/data/server/log/DirLevel1/", 02770) = 0
5864  socket(PF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0) = 15
5864  connect(15, {sa_family=AF_LOCAL, sun_path="/var/run/nscd/socket"}, 110) = -1 ENOENT (No such file or directory)
5864  close(15)                         = 0
5864  socket(PF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0) = 15
5864  connect(15, {sa_family=AF_LOCAL, sun_path="/var/run/nscd/socket"},  110) = -1 ENOENT (No such file or directory)
5864  close(15)                         = 0
5864  open("/etc/group", O_RDONLY|O_CLOEXEC) = 15
5864  fstat(15, {st_mode=S_IFREG|0644, st_size=652, ...}) = 0
5864  mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f414d7c4000
5864  read(15, "root:x:0:\nbin:x:1:\ndaemon:x:2:\ns"..., 4096) = 652
5864  close(15)                         = 0
5864  munmap(0x7f414d7c4000, 4096)      = 0
5864  chown("/home/svtest2/data/server/log/DirLevel1/", 4294967295, 100) = 0
5864  write(7, "\0\0\2~\6\0\0\0\0\0\21i\216\376\377\377\377\377\377\377\377\1\0\0\0\0\0\0\0\1\0\0"..., 638) = 638
5864  read(7, "\0\0\0\300\6\0\0\0\0\0\10\0\0\0\0\250\0\0\0\0\0\0\0\0\0(\0\0\0\0\0\0"..., 8208) = 192
5864  write(7, "\0\0\1}\6\0\0\0\0\0\3h\221\1\0\0\0\0\0\0\0\376\377\377\377\377\377\377\377\250\0\0"..., 381) = 381
5864  read(7, "\0\0\0\26\6\0\0\0\0\0\10\4\0\0\0\t\1\0\0\0\215\f", 8208) = 22
5864  msgsnd(43679799, {805306373, "y\0\0\0007\200\232\2\0\0\0\0\f\2\0\0\0\0\0\200\0\0\0\0\0\0\0\0\0\0\0\0"...}, 516, IPC_NOWAIT) = 0
5864  msgrcv(43614264,

From http://man.sourcentral.org/RHEL7/2+chown,

When the owner or group of an executable file are changed by an unprivileged user the S_ISUID and S_ISGID mode bits are cleared. POSIX does not specify whether this also should happen when root does the chown(); the Linux behavior depends on the kernel version. In case of a non-group-executable file (i.e., one for which the S_IXGRP bit is not set) the S_ISGID bit indicates mandatory locking, and is not cleared by a chown().

The above highlights a possible scenario, but I'm not sure how that is applicable to my case because it is not executable file but a directory.

Community
  • 1
  • 1
Phalgun
  • 1,181
  • 2
  • 15
  • 42
  • Whether it's expected behavior or a bug, surely the workaround is very easy: just call `chmod` again. – Nate Eldredge Apr 19 '16 at 03:52
  • In Linux, everything is a file (file, directory, etc..). There is no distinction whether it is a file or directory where ` S_IXGRP` is not set. It is either set, or not. It looks like sentence 1 applies and you, as an unprivileged user, attempt to create a new file under a set_gid directory (and thus change its group pursuant to the `S_ISGID` bit on the parent directory) which has the effect of clearing the bits. That's my reading. Try running as root and see if the permissions stick. – David C. Rankin Apr 19 '16 at 04:39
  • I have tried running chown as root as yes the permissions remain as is(updated the question above). I have not been able to add CAP_CHOWN capability to a non-privileged user. – Phalgun Apr 19 '16 at 14:33

1 Answers1

0

Since *nix system consider a file to be an executable by seeing the 'x' permission bit, I believe a searchable directory might be considered as an executable, too.

GMichael
  • 2,726
  • 1
  • 20
  • 30
  • Sheesh... With a directory the `x` controls *descend into* permission. Thus the `x` bit on either *user*, *group* or *world* controls whether *user*, *group* or *world* can descend into (i.e. read the contents of) the directory. – David C. Rankin Apr 19 '16 at 04:23