Osmc sudoers NOPASSWD

I think you have mis-understood me. Whether or not kodi runs as root or osmc with nopasswd sudo enabled is irrelevant. Plugins are written in Python and it is relatively trivial to create a python script which can open a port outbound to a control center and then be used as a bot. None of that needs elevated privileges and so removing elevated privileges won’t solve the issue.

As @sam_nazarko says, if you’re so confident that you can fix this in the time it takes to write the post in a way that is modular enough to support whatever new functionality needs to be added to MyOSMC over time (remember most users use only the GUI so everything must be able to be done there), then clone the repo, fix it, build it, test it and submit a PR! So long as it works then no-one will argue that it would be a valued contribution. Good luck!

As @DBMandrake pointed out OSMC isn’t “any linux system”. It is designed as a closed single user system that happens to use linux as it’s source.

As for me, no I’m not a kodi developer, but I am a linux user with over 20 years experience and I have an IT security operations background.

All that said, if you can prove me wrong and resolve it without hampering the interface in a way that works with every skin on every supported device and without introducing other security holes then nothing would make me happier!

We need to make improvements to it that are actually security improvements.
This takes time, and testing to make sure things work properly. There will always need to be a compromise between convenience / ease of use and security.

It is not necessarily trivial. If you would like to help with this, then the suggestions above would be a good start.

I will make a suggestion and proof of concept which then can then be easily be extended. I will reply later this evening with first details :slight_smile: Actually I am happy about that vivid discussion already.

In the meantime:

Can we add the sbin directories to the normal user path in /etc/login.defs ?
Just like this:

ENV_PATH PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin:/usr/local/games:/usr/games

It freaks me out, that I need to type e.g. ‘/sbin/sudo reboot’ instead of just ‘sudo reboot’ like in my ubuntu.

m.

sudo reboot works fine here. Are you using a shell other than bash?

/etc/profile is not sourced on my box. I am using bash

osmc@osmc:~/osmcctrl$ env | grep SHELL
SHELL=/bin/bash

@ActionA:
I can’t do any new post as the max amount of #16 posts is reached for today :slight_smile:
About the path problem: Can you post the result of ‘env | grep PATH’. As you point out, sbin is not set in your /etc/login.defs …

osmc@osmctestpi:~$ cat /etc/login.defs | grep ENV_PATH
# Three items must be defined:  MAIL_DIR, ENV_SUPATH, and ENV_PATH.
ENV_PATH        PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games
osmc@osmctestpi:~$ sudo reboot

What you are asking for is not necessary as my box has no issue with sudo reboot. You’ve broken something.

2 Likes

Just tested SSH and local console, both behave as expected.

1 Like

Good Morning Guys,

I have the following suggestion to restrict the permissions to only the necessary by having a single little c programm:

It has multiple symbolic links pointing at a single binary called ‘osmcctrl’, for different tasks. Thats the way also busybox is implemented.

It keeps all code together in one cozy c-file. Here what it looks like in the filesystem:

osmc@osmc:~/osmcctrl$ ls -la
total 32
drwxr-xr-x  2 osmc osmc 4096 Feb  2 14:43 .
drwxr-xr-x 23 osmc osmc 4096 Feb  2 14:41 ..
-rw-r--r--  1 osmc osmc  549 Feb  1 22:09 Makefile
lrwxrwxrwx  1 osmc osmc    8 Feb  1 22:14 osmc_reboot -> osmcctrl
lrwxrwxrwx  1 osmc osmc    8 Feb  1 22:14 osmc_servicedisable -> osmcctrl
lrwxrwxrwx  1 osmc osmc    8 Feb  1 22:14 osmc_serviceenable -> osmcctrl
lrwxrwxrwx  1 osmc osmc    8 Feb  1 22:14 osmc_servicestart -> osmcctrl
lrwxrwxrwx  1 osmc osmc    8 Feb  1 22:14 osmc_servicestop -> osmcctrl
lrwxrwxrwx  1 osmc osmc    8 Feb  1 22:14 osmc_sethostname -> osmcctrl
lrwxrwxrwx  1 osmc osmc    8 Feb  1 22:14 osmc_setlocale -> osmcctrl
lrwxrwxrwx  1 osmc osmc    8 Feb  1 22:14 osmc_settimezone -> osmcctrl
-rwsr-xr-x  1 root root 8732 Feb  1 22:14 osmcctrl

Note that the SUID bit is set on osmccctrl and its owned by root.

sudo chown root:root osmcctrl && sudo chmod 4755 osmcctrl

So far the following functionality has been implemented:

  • Rebooting by calling “osmc_reboot”
  • Setting the timezone by calling “osmc_setimezone Europe/Berlin”
  • Setting the hostname “osmc_sethostname marvin”
  • Start/Stop/En-/Disable a service calling e.g:
    “osmc_enable ssh”
    “osmc_disable ssh”

    BTW: Quering the status or is-enabled of a system service is in general not restricted to root. So to figure out if a service is running: “systemctl status ssh” or also “systemctl is-enabled ssh” can be issued as user osmc. A wrapper is not needed.

Having all “sudo” hacks in one file actually builds something like an interface. It makes it easy to track which components are messing with the system. It also makes it easy to adopt to future needs.

Now, for the tiny implementation… And finally tell me if you would consider this solution!

 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>

 #include <unistd.h>
 #include <linux/reboot.h>


void
osmcSetTimezone (int argc, char **argv)
{
  if (argc != 2)
    {
      fprintf (stderr, "no timezone given!\n");
      exit (-1);
    }


  printf ("Setting timezone to '%s'\n", argv[1]);

  /* Keep /etc/timezone in sync */
  FILE *fp = fopen ("/tmp/timezone", "w");
  if (fp)
    {
      fprintf (fp, "%s\n", argv[1]);
      fclose (fp);
      int res = system ("/bin/mv /tmp/timezone /etc/timezone");	/* We need this to update a root owned file */
      if (res == 0)
	{
	  char *command;
	  asprintf (&command, "%s%s%s", "/bin/cp /usr/share/zoneinfo/",
		    argv[1], " /etc/localtime.dpkg-new");
	  system (command);
	  system ("/bin/mv /etc/localtime.dpkg-new /etc/localtime");
	}
    }
}

void
osmcSetLocale (int argc, char **argv)
{
  printf ("Setting locale... TODO\n");
}

void
osmcSetHostname (int argc, char **argv)
{
  if (argc != 2)
    {
      fprintf (stderr, "no hostname given!\n");
      exit (-1);
    }

  printf ("Setting hostname\n");

  FILE *fp;
  fp = fopen ("/tmp/hostname", "w");
  if (fp)
    {
      fprintf (fp, "%s", argv[1]);
      fclose (fp);
    }
  else
    return;

  system ("/bin/mv /tmp/hostname /etc/hostname");
  system ("/bin/hostname -F /etc/hostname");
}

void
osmcReboot (int argc, char **argv)
{
  reboot (LINUX_REBOOT_CMD_RESTART);
}

void
osmcServiceCmd (char *cmd, int argc, char **argv)
{
  char syscmd[128 * 2];

  if (argc != 2)
    {
      fprintf (stderr, "no servicename given!\n");
      exit (-1);
    }

  if (strlen (argv[1]) > 128)
    {
      fprintf (stderr, "servicename too long!\n");
      exit (-1);
    }

  sprintf (syscmd, "systemctl %s %s", cmd, argv[1]);
  system (syscmd);
}


void
osmcExec (int argc, char **argv)
{
  system(argv[1]);
}


int
main (int argc, char **argv)
{
  printf ("Called: %s\n", argv[0]);

  // besides suid we need to have root group and user id 
  uid_t uid = 0;   
  gid_t gid = 0;

  setuid(uid);
  setgid(gid);
	

  if (strstr (argv[0], "osmc_settimezone"))
    osmcSetTimezone (argc, argv);
  else if (strstr (argv[0], "osmc_setlocale"))
    osmcSetLocale (argc, argv);
  else if (strstr (argv[0], "osmc_sethostname"))
    osmcSetHostname (argc, argv);

  else if (strstr (argv[0], "osmc_reboot"))
    osmcReboot (argc, argv);

  else if (strstr (argv[0], "osmc_serviceenable"))
    osmcServiceCmd ("enable", argc, argv);
  else if (strstr (argv[0], "osmc_servicedisable"))
    osmcServiceCmd ("disable", argc, argv);
  else if (strstr (argv[0], "osmc_servicestart"))
    osmcServiceCmd ("start", argc, argv);
  else if (strstr (argv[0], "osmc_servicestop"))
    osmcServiceCmd ("stop", argc, argv);

#ifdef MYDEBUG
  else if (strstr (argv[0], "osmc_exec"))
    osmcExec ( argc, argv);
#endif

  else
    fprintf (stderr, "Command not found\n");

}
1 Like

A C program introduces a binary element, which means it will need to be compiled for each system.

A better way to would be to create a parameterised systemd target to call a bash script which checks args and performs some action based on this.

With the new My OSMC, we could have a daemon which runs as root and only allows certain actions, and communicate with it via DBus.

Sam

@sam_nazarko

Script would be easier to maintain, but as @DBMandrake pointed out: SUID is not possible on (bash) scripts.

Is there actually no platform specific compiling happening when building the OSMC packages?
The programm itself is just plain c. That wouldn’t be a problem for any compiler nor would be the dependencies.

greetz m.

There is platform specific compiling, but it would introduce a need for a new package.

SUID is not necessary for scripts. Just use systemd parameterised targets, and invoke there. We need to get PolKit to support systemd control of start and stop from a non privileged user. This has been the plan for a little while.

Long term goal is a C++ library with SWIG for Python interfacing.

It’s being worked on, but will take some time

Sam

Feel free to use the proposed solution. Keep it simple stupid - K.I.S.S.

Hello!
I also have concerns about Kodi and addons with full root privilege over a Linux network stack in my LAN. After reading this thread I think there is a solution without using gcc.

sudoers rules are pretty flexible, so I tried this:

sudo nano /usr/osmc/bin/osmc-settimezone      # and add the following two lines:
#!/bin/bash
echo >/etc/timezone "$1"

sudo chmod 700 /usr/osmc/bin/osmc-settimezone

sudo nano /etc/sudoers.d/osmc-sudo-scripts    # and add the following line:
osmc   ALL=(ALL) NOPASSWD: /usr/osmc/bin/osmc-settimezone

Now the general NOPASSWD rule can be removed, and /etc/timezone can still be rewritten without a password:

sudo rm /etc/sudoers.d/osmc-no-sudo-password
sudo -n osmc-settimezone "Europe/Zurich"

Because the script is owned by root, it can only be edited by root. And if /etc/timezone has been created by this script it is also owned by root and read-only for other users.

What do you think?

But it still lets me elevate privileges via the settimezone script.

If you can try your changes and want it reviewed then a pull request would be useful

Sam

It’s just an idea atm. I’d be glad to help OSMC, but I did not look into its code yet. Do you have any hints where to look for operations that need root privilege?

What do you have in mind about elevate privilege via the script? If directory /usr/osmc/bin and all scripts are read-only for non-root users then there is no danger anymore, isn’t it?
Of course the scripts must be carefully protected against malicious inputs like ${1} or files or others.

I know I’m a bit late to the party, but since it hasn’t already been mentioned anywhere in this thread. it’s just possible that systrace might fulfil the requirement for having Kodi run as an unprivileged process but with the capability for limited privilege escalation based upon a pre-defined policy. Whether it would be worth the effort required to implement systrace within OSMC is another matter entirely.

http://www.citi.umich.edu/u/provos/systrace/

Thinking about it, I still think the best approach is:

  • parameterised systemd targets to allow copying of files in to privileged locations from /home/osmc/.settings
  • adjust PolKit so that OSMC user can start these services.

Then you can do something like:

  • Write timezone to /home/osmc/.settings/tzdata
  • systemctl start settings-change@tzdata, and have a one-shot systemd unit handle the move.