Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Strange result when running a program as a root

Tags:

c

linux

ubuntu

Here's a full source of a program that demonstrates my problem (the OS is Ubuntu 14.04 32-bit if it matters):

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>

int main(int argc, const char *argv[])
{
   int status, fd;

   printf("CURRENT UID: %d, CURRENT GID: %d\n", getuid(), getgid());

   fd = open("/dev/ttyS0", O_WRONLY);
   if(fd < 0)
   {
      printf("Error opening /dev/ttyS0: %s\n", strerror(errno));
      return 1;
   }
   printf("Successfully opened /dev/ttyS0\n");
   close(fd);

   /* DROP PRIVILEGES */

   setgid(1000);
   setuid(1000);

   printf("CURRENT UID: %d, CURRENT GID: %d\n", getuid(), getgid());

   fd = open("/dev/ttyS0", O_WRONLY);
   if(fd < 0)
   {
      printf("Error opening /dev/ttyS0: %s\n", strerror(errno));
      return 1;
   }
   printf("Successfully opened /dev/ttyS0\n");
   return 0;
}

There are two users in the system: root and a regular, non-root user (let's call him "ubuntu") with id=1000. The above program is trying to open a serial port (/dev/ttyS0) twice: first time as root or ubuntu (depending on how it's invoked) and second time always as ubuntu. First unsuccessful attempt causes the program to abort. User ubuntu is a member of dialout group so theoretically he has necessary permissions to open /dev/ttyS0. I invoke the program in four different ways:

1) run directly as ubuntu

invocation:

<path to my program>

2) run as ubuntu, but using sudo

invocation:

sudo -u ubuntu <path to my program>

3) run as root, but with privileges dropped to those of ubuntu (so, effectively, run as ubuntu):

invocation:

sudo su
sudo -u ubuntu <path to my program>

In all three cases I get the following expected result:

CURRENT UID: 1000, CURRENT GID: 1000
Successfully opened /dev/ttyS0

CURRENT UID: 1000, CURRENT GID: 1000
Successfully opened /dev/ttyS0

In the last case, however, something strange happens:

4) run directly as root

invocation:

sudo su
<path to my program>

result:

CURRENT UID: 0, CURRENT GID: 0
Successfully opened /dev/ttyS0

CURRENT UID: 1000, CURRENT GID: 1000
Error opening /dev/ttyS0: Permission denied

Of course it's the last two lines of the output that I don't understand: this time, when root drops his privileges, it turns out that ubuntu has insufficient privileges to open /dev/ttyS0, but why? How is this case different from cases 1-3?

One last thing worth mentioning: if I change this line of my code:

setgid(1000);

to this:

setgid(20); /* 20 is the id of dialout group */ 

then the last attempt to open /dev/ttyS0 is successful as well.

Does it mean the information about ubuntu being a member of dialout group gets lost for some reason when I run the program as root and then drop privileges to those of ubuntu by changing uid and gid to 1000? Can you please give me a detailed explanation of what happens in case 4 of my example and why the result is different than I expected?

like image 954
Peter Avatar asked Oct 30 '22 10:10

Peter


1 Answers

Setting the userid and groupid does not set all supplementary groups (i.e. all groups, which are not the main group of the user but assigned to him in /etc/groups) automagically. Try to use

initgroups("ubuntu", 1000);

prior to the setgid()-call. Then the process should have the privileges of the dialout-group.

like image 173
Ctx Avatar answered Nov 01 '22 22:11

Ctx