Controlling Shared Processes

Starting out a new year and I want to finish up what I started on team collaboration on unix systems. The last two posts have been dedicated to working in a shared directory using groups. When I started those, I had several use cases that I thought I would be able to knock off pretty quickly.

For reference, here are the use cases that I want to cover.

  • Share edit files: As a team of developers, we want to edit the same file (usually a configuration file).

  • Adding group perms: As a team of developers, we want to add new files and not have to always remember to change the group for each file.

  • Disallow intruders: As a team of developers, we do not want someone that is not part of the team to have write or delete permission to our working directory.

  • Modifying old files to add group: As a team of developers that have started out using ugo+rwx on all our files, we want to switch over to using a group and reduce our permissions down just the group (o-rwx)

  • Run a script as group: As a team of developers, we want anyone on the team to run a script and anyone else on the team is permitted to kill and restart the script

Run a script as a group

To get into this one, I need to set the stage and demonstrate the problem that Moss and Roy face as a team that is collaborating. To do that, I’m going to fire up my docker image, and write a quick little script that runs indefinitely and writes a file to a log directory.

Reminder and setup

To remind you where we started from, here is are our cast of characters, Moss, Roy and Jen:

[root /]$ id moss
uid=1000(moss) gid=1000(moss) groups=1000(moss),1003(stealth)

[root /]$ id roy
uid=1001(roy) gid=1001(roy) groups=1001(roy),1003(stealth)

[root /]$ id jen
uid=1002(jen) gid=1002(jen) groups=1002(jen)
[root /]$ 

Notice that Moss and Roy both are members of the stealth group and Jen is not a member of that group.

Here is the project directory setup:

[root /]$ ls -al /mnt/reynholm/
total 8
drwxrws--- 2 moss stealth 4096 Jan  5 17:15 .
drwxr-xr-x 3 root root    4096 Dec 31 19:38 ..

Notice that Mos owns the /tmn/reynholm directory and currently there isn’t anything in the directory – which we’ll change shortly.

Simple server script

Here is my very simple python server script. No this isn’t a real server, it doesn’t have all those bells, it’s just a process that should run indefinitely and emits some information to a log file.

#!/bin/python

import time
import datetime
import logging
logging.basicConfig(filename='./log/data.log', level=logging.DEBUG)

while(1):
    logging.debug("CurrentTime:{}  euid:{} egid:{}".format(datetime.datetime.now(),os.geteuid(),os.getegid()))
    time.sleep(30)

Moss used vi to create the file and he saved it in the ‘/mnt/reynholm` directory.

[moss /]$ ls -al /mnt/reynholm/
total 12
drwxrws--- 2 moss stealth 4096 Jan  5 17:24 .
drwxr-xr-x 3 root root    4096 Dec 31 19:38 ..
-rw-rw---- 1 moss stealth  223 Jan  5 17:24 TheInternet.py

Notice that the server TheInternet.py is read write for user and group. It does have a ‘shebang’ line at the top: #!/bin/python so it should be runnable from the command line if the execute bits are set on the file. Both Moss and Roy don’t want to bother with running python TheInternet.py so Moss changes the name to TheInternet and sets the execute bits on the file. He also creates the log directory that will contain the log files which demonstrate the program is running.

[moss /]$ mv /mnt/reynholm/TheInternet.py /mnt/reynholm/TheInternet

[moss /]$ chmod ug+x /mnt/reynholm/TheInternet 

[moss reynholm]$ mkdir /mnt/reynholm/log

[moss reynholm]$ ls -al /mnt/reynholm/
total 16
drwxrws--- 3 moss stealth 4096 Jan  5 17:34 .
drwxr-xr-x 3 root root    4096 Dec 31 19:38 ..
-rwxrwx--- 1 moss stealth  224 Jan  5 17:32 TheInternet
drwxrws--- 2 moss stealth 4096 Jan  5 17:34 log

Moss starts up the program and pushes it to the background using the & operator.

[moss reynholm]$ ./TheInternet &

[moss reynholm]$ pgrep -a TheInternet
2154 /bin/python ./TheInternet

[moss reynholm]$ tail ./log/data.log
DEBUG:root:CurrentTime:2019-01-06 20:10:52.913498  euid:1000 egid:1000
DEBUG:root:CurrentTime:2019-01-06 20:11:22.943739  euid:1000 egid:1000
DEBUG:root:CurrentTime:2019-01-06 20:11:52.974058  euid:1000 egid:1000

The process appears to be running in the background now and writing to the log file. It should not terminate if Moss logs off and Roy logs in.

[root reynholm]$ su roy

[roy reynholm]$ ps
  PID TTY          TIME CMD
 2160 ?        00:00:00 bash
 2173 ?        00:00:00 ps

[roy reynholm]$ pgrep -a TheInternet
2154 /bin/python ./TheInternet

Notice that Roy initially couldn’t see the process using just a ps command. Because he does not own the process. However if he uses pgrep to search for the process using a know expression he is able to see the processes that Moss is running.

Roy can also look at the log file because both Roy and Moss are in the same group and the log directory is readable by the group.

[roy reynholm]$ tail -f ./log/data.log
DEBUG:root:CurrentTime:2019-01-06 20:10:52.913498  euid:1000 egid:1000
DEBUG:root:CurrentTime:2019-01-06 20:11:22.943739  euid:1000 egid:1000
...
DEBUG:root:CurrentTime:2019-01-06 20:13:23.029303  euid:1000 egid:1000
<ctrl-c>

Stage is set

Ok, so now for the big question, can Roy control the process that Moss started? Let’s say that Moss is unavailable at the moment and Roy would like to make a code change to the script and start it backup.

I imagine he would do this by killing the process, editing the file and starting it backup:

[roy /]$ ps -u moss
  PID TTY          TIME CMD
 2154 ?        00:00:00 TheInternet
[roy /]$ kill 2154
bash: kill: (2154) - Operation not permitted

Well, that didn’t work that way. On deeper inspection of the script that Moss ran, I can see that the process is owned by Moss (uid:1000) and that the group is the moss group (gid:1000) not the stealth group (gid: 1003). So Roy (uid:1001) has no permission to control TheInternet even though the process was started in the group directory /mnt/reynholm.

[roy /]$ ps -o uid,gid,pid,cmd 2154
  UID   GID   PID CMD
 1000  1000  2154 /bin/python ./TheInternet

The wikipedia documentation indicates that this is, in fact, expected behavior because of a potential security hole. Modern unix systems do not allow a script to take on the group permission. However this wikipedia link indcates that: Although it is still possible for a binary executable to assume the group permission. However this assertion is rejected by other threads.

Binary Process Assume Group id

So which is it? Can a binary process be controlled using setguid and group ownership or not. Roy decided to test this out. By writing a simple go binary program that is very similar to the python script TheInternet. Moss and Roy will find out if they could have shared control over the binary.

The small little docker linux system didn’t have Go so I installed it and added it to the path.

[root /]$ curl https://dl.google.com/go/go1.11.4.linux-amd64.tar.gz > /tmp/go1.11.4.linux-amd64.tar.gz
...

[root /]$ tar -C /usr/local -xzf /tmp/go1.11.4.linux-amd64.tar.gz
...
[root /]$ export PATH=$PATH:/usr/local/go/bin

[root /]$ 

[root /]$ go version
go version go1.11.4 linux/amd64

Roy fires up emacs1 and developed the following go program.

package main

import (
  "log"
  "time"
  "os"
)

func main() {
  log.SetPrefix("Reynholm:TheInternet:")
  log.SetFlags(log.Llongfile | log.LUTC | log.Ldate | log.Ltime)

  fh,err := os.Create("./log/godata.log")
  if err != nil {
    log.Fatal(err)
  }
  log.SetOutput(fh)
  for {
    log.Printf("euid:%d egid:%d",os.Geteuid(),os.Getegid())
    time.Sleep(30 * time.Second)
  }
}

He then compiles the go program into an executable

[roy reynholm]$ go build TheInternetGo.go
[roy reynholm]$ ls -al
total 2008
drwxrws--- 3 moss stealth    4096 Jan  6 20:31 .
drwxr-xr-x 3 root root       4096 Dec 31 19:38 ..
-rwxrwx--- 1 moss stealth     277 Jan  6 20:02 TheInternet
-rwxrwx--- 1 roy  stealth 2034792 Jan  6 20:31 TheInternetGo
-rw-rw---- 1 moss stealth     381 Jan  6 17:07 TheInternetGo.go
drwxrws--- 2 moss stealth    4096 Jan  6 20:10 log

Just to make sure that the group id is responsible for the process, Roy sets the setgid bit for TheInternetGo binary.

[roy reynholm]$ chmod g+s TheInternetGo
[moss /]$ ls -l /mnt/reynholm/TheInternetGo
-rwxrws--- 1 roy stealth 2034792 Jan  6 20:31 /mnt/reynholm/TheInternetGo

The he fires up the process in the background.

[roy reynholm]$ ./TheInternetGo &
[1] 2334

[roy reynholm]$ tail -f log/godata.log 
Reynholm:TheInternet:2019/01/06 20:34:13 /mnt/reynholm/TheInternetGo.go:19: euid:1001 egid:1003

Now Moss tries to kill the process.

[roy reynholm]$ exit
exit

[root /]$ su moss

[moss /]$ pgrep TheInternetGo
2334

[moss /]$ kill 2334
bash: kill: (2334) - Operation not permitted

Nope. The thread. asserting that no user can kill another users’ process appears to be correct.

The final assertion here is:

Using setguid group permissions, it is not possible for Moss to kill a process started by Roy and conversely, it is not possible for Roy to kill a process started by Moss.

Conclusions

Well, so what I know now is that although setguid bit is useful for group collaboration on files and directories, it does not enable members of the group to control processes started by other members of the group. Regardless of whether those processes are scripts or binaries.

Ok so my final use-case is still unsatisified.

  • Run a script as group: As a team of developers, we want anyone on the team to run a script and anyone else on the team is permitted to kill and restart the script

Next post, I’ll head down a different path that should address this final use case.

Here are the related posts so far.

Reference

https://superuser.com/questions/137207/how-to-kill-a-process-started-with-a-different-user-without-being-root-or-sudoer https://en.wikipedia.org/wiki/Group_identifier https://wiki.centos.org/TipsAndTricks/BecomingRoot https://en.wikipedia.org/wiki/Setuid#Effects_of_setuid_and_setgid http://man7.org/linux/man-pages/man5/acl.5.html https://golangcode.com/while-true/ https://blog.scalyr.com/2018/06/go-logging/


  1. emacs The one true text editor. Moss and Roy fight about it all the time. ↩︎