Update, 18 oct, How to request special priority for a process in C. - 18/10/2009, 11:36

As per usual, estimates don't quite meet. Real life happened, which means that the supposed 1 week estimate to arrival for the new classes has been long overdue for more than a month (eek!). Also contributing to this is the fact that upon discussion with some friends, some changes were suggested. I think I'll just upload it as-is now, along with some bugfixes, and modify it later.

I also finished a small article on how to request special priority for a process in GNU/Linux using C, which is in Spanish at the Lidsol log.

Here's the translation
Sometimes it's necessary for a program to run with a higher priority than usual (for example: media players that do not attempt world domination); it can be the case that executing the "renice" command on a terminal is not enough.
Such cases require asking the scheduler for special treatment.

According to POSIX, the following policies exist to determine how a process is treated:

-- Normal policy --
SCHED_OTHER - Ordinary "round-robin" algorithm

-- "real time" policy --
SCHED_FIFO - "first in first out"
SCHED_RR - real-time "round-robin"

Aditionally, in Linux 2 more options are defined as "normal" policies (see the sched_set_scheduler manual page for more info).

The sched.h header contains the subroutine that will be used to change the priority of a process:

sched_setscheduler(processID, policy, schedulerParameter);

- processID will be 0 if the current process is to be affected
- policy is either SCHED_FIFO o SCHED_RR according to our requirements
- the scheduler parameter is a pointer to a struct sched_param variable containing the priority that we wish our process to have while executed

To find out what priorities are available for a specific policy, we must use the next subroutines:
sched_get_priority_max(policy)
and
sched_get_priority_min(policy)

Care must be taken when assigning a real-time priority to a process: if an infinite loop occurs, it might be very hard or even impossible to stop the process from taking over the world processor.

Once the desired priority has been decided, it must be stored in a struct sched_param variable in the field sched_priority; this variable will be used with the sched_setscheduler(processID, policy, priority) subroutine.

Considering that only the superuser can give/be given special priority, we must set our compiled executable to have setuid attributes in the filesystem, that is, when executed, it should take the superuser's identity. This can be achieved executing the following commands in a terminal:

1) Set the superuser as the owner of the executable ( #chmod root program )
2) Set the executable as setuid ( # chmod +s program )

Great care must be taken when programming these kind of applications because any user who can execute it will do so as root; therefore the program must revoke its superuser privileges as soon as possible.

To revoke special privileges, the setreuid function will be used just after we have finished setting the process's priority (More info on effective/real user IDs is available here: allexperts).

Revoking superuser privileges is also a requirement to initialise GTK+, as explained here: http://www.gtk.org/setuid.html.

To wrap everything up, here's a snipped showing how it's done:
--

[code='C']
/*

prio.c

Program to demonstrate priority change and
privilege revoking.

How to compile:
gcc prio.c -o prio

Don't forget to setuid it root
sudo chown root prio
sudo chmod +s prio

so that it works correctly

*/

#include <stdlib.h>
#include <stdio.h>
#include <sched.h> // priority change
#include <errno.h> // error reporting


/* etc. */

int main(int argc, char *argv[])
{
   // Variables to store the desired priority
   struct sched_param wish;
   int wishlimit;

   wishlimit = sched_get_priority_max(SCHED_FIFO);

   wish.sched_priority = wishlimit/20; /* Less than maximum priority
    but still better than a normal process*/

   /* Who are we? right now we should be root */
   printf("UID %d, EUID: %d\n", getuid(), geteuid());

   /* Perform priority change */
   if (sched_setscheduler(0, SCHED_FIFO, &wish))
    printf("sched_setsched: %s\n", strerror(errno));

   /* Revoke privileges */
   setreuid(getuid(), getuid());

   /* ┬┐Have we revoked privileges yet? */
   printf("UID %d, EUID: %d\n", getuid(), geteuid());

   /*
    Rest of the program
    ...
    etc.
   */

   return 0;
}

< Back to blog

This site doesn't use cookies, does not log IPs and does not track you in any way.