Reputation: 10507
A very simple test code piece:
#include<unistd.h>
#include<sys/resource.h>
#include<sys/syscall.h>
#include<sys/types.h>
#include<stdio.h>
int main()
{
int i=0;
pid_t pid=getpid();
pid_t tid=syscall(SYS_gettid);
printf("%d,%d\n",pid,tid);
setpriority(PRIO_PROCESS,0,-2);
while(true){
++i;
}
return 0;
}
setpriority is using '0' as second parameter,indicating current process, as per the man page:
The value which is one of PRIO_PROCESS, PRIO_PGRP, or PRIO_USER, and
who is interpreted relative to which (a process identifier for
PRIO_PROCESS, process group identifier for PRIO_PGRP, and a user ID for
PRIO_USER). A zero value for who denotes (respectively) the calling
process, the process group of the calling process, or the real user ID
of the calling process. Prio is a value in the range -20 to 19 (but
see the Notes below). The default priority is 0; lower priorities
cause more favorable scheduling.
Compile and run it, inside "top" command, the "PR" value of "a.out" is still 20, not being set with "20-2" as I expected.
Is my "setpriority" taking effect?
Upvotes: 0
Views: 1887
Reputation: 2403
My first advice is to check the return value of setpriority()
to see if it returned an error. My expectation is that it is indicating an error by returning -1
and that checking errno
would reveal that EACCES
was the error indicating that the caller did not have the required privilege.
There are three ways to fix this:
1) Make the executable SUID root or run it with sudo (not secure).
2) Grant the executable the capability CAP_SYS_NICE
(e.g. sudo setcap cap_sys_nice=ep <executable>
).
3) Adjust the hard and soft limits for the shell (ulimit
) or user (depending on distro /etc/security/limits.conf
). Or just adjust the hard limit and let the program adjust the soft limit.
Note that SUID and file capabilities are not effective on partitions mounted with nosuid
(encrypted home directories often are).
EDIT: @TrentP has pointed out that you can drop privileges. Below is some code that is a fair example of how to do this, although it works for real-time priority:
/*
* Set_policy_priority
*
* This is used to set the priority and policy for the real-time
* scheduler. This normally requires some form of privilege, as the
* default hard ulimit of 0 will prevent an unprivileged program from
* doing so.
*
* The most secure thing to do is grant the executable the potential
* to enable CAP_SYS_RESOURCE (with sudo setcap cap_sys_resource=p
* <executable>). If it is needed, this routine will enable the
* capability, raise the hard limit, and then irrevocably drop the
* privilege.
*
*/
int set_policy_priority(int policy, int priority, int nofiles) {
const cap_value_t cap_vector[1] = { CAP_SYS_RESOURCE };
cap_t privilege_dropped = cap_init();
cap_t privilege_off = cap_dup(privilege_dropped);
cap_set_flag(privilege_off, CAP_PERMITTED, 1, cap_vector, CAP_SET);
cap_t privilege_on = cap_dup(privilege_off);
cap_set_flag(privilege_on, CAP_EFFECTIVE, 1, cap_vector, CAP_SET);
struct sched_param param;
struct rlimit rl;
int e, min, max;
// See if priority we want is in the range offered by SCHED_FIFO
min = sched_get_priority_min(policy);
max = sched_get_priority_max(policy);
if (verbose) {
fprintf(stderr, "For policy SCHED_FIFO min priority is %d, max is %d.\n", min, max);
}
if ((min>priority)||(max<priority)) {
fprintf(stderr, "Desired priority of %d is out of range.\n", priority);
return 1;
}
// See if the RTPRIO limits allows the priority we want
if (getrlimit(RLIMIT_RTPRIO, &rl) != 0) {
e = errno;
fprintf(stderr, "Failed to getrlimit(): %s.\n", strerror(e));
return 1;
}
if (verbose) {
fprintf(stderr, "RTPRIO soft limit is %d, hard is %d.\n",
(int) rl.rlim_cur, (int) rl.rlim_max);
}
// Adjust hard limit if necessary
if (rl.rlim_max < priority) {
if (cap_set_proc(privilege_on) != 0) {
fprintf(stderr, "Need to raise RTPRIO hard limit, but can't enable CAP_SYS_RESOURCE.\n");
return 1;
}
rl.rlim_max = priority;
if (setrlimit(RLIMIT_RTPRIO, &rl) != 0) {
e = errno;
fprintf(stderr, "Failed to raise hard limit for RTPRIO to %d: %s.\n",
(int) rl.rlim_max, strerror(e));
return 1;
}
if (cap_set_proc(privilege_off)) {
fprintf(stderr, "Failed to turn off privileges.\n");
return 1;
}
if (verbose) {
printf("Raised hard limit for RTPRIO to %d.\n", (int) rl.rlim_max);
}
}
// Adjust soft limit if necessary
if (rl.rlim_cur < priority) {
rl.rlim_cur = priority;
if (setrlimit(RLIMIT_RTPRIO, &rl) != 0) {
e = errno;
fprintf(stderr, "Failed to raise soft limit for RTPRIO to %d: %s.\n",
(int) rl.rlim_cur, strerror(e));
return 1;
}
if (verbose) {
printf("Raised soft limit for RTPRIO to %d.\n", (int) rl.rlim_cur);
}
}
// Set desired priority with class SCHED_FIFO
param.sched_priority = priority;
if (sched_setscheduler(0, policy, ¶m) != 0) {
e = errno;
fprintf(stderr, "Setting policy failed: %s.\n", strerror(e));
return 1;
} else if (verbose) {
printf("Set policy SCHED_FIFO, priority %d.\n", param.sched_priority);
}
// See if the NOFILE limits allows the number of fds we want
if (getrlimit(RLIMIT_NOFILE, &rl) != 0) {
e = errno;
fprintf(stderr, "Failed to getrlimit(): %s.\n", strerror(e));
return 1;
}
if (verbose) {
fprintf(stderr, "NOFILE soft limit is %d, hard is %d.\n",
(int) rl.rlim_cur, (int) rl.rlim_max);
}
// Adjust hard limit if necessary
if (rl.rlim_max < nofiles) {
if (cap_set_proc(privilege_on) != 0) {
fprintf(stderr, "Need to raise NOFILE hard limit, but can't enable CAP_SYS_RESOURCE.\n");
return 1;
}
rl.rlim_max = nofiles;
if (setrlimit(RLIMIT_NOFILE, &rl) != 0) {
e = errno;
fprintf(stderr, "Failed to raise hard limit for NOFILE to %d: %s.\n",
(int) rl.rlim_max, strerror(e));
return 1;
}
if (cap_set_proc(privilege_off)) {
fprintf(stderr, "Failed to turn off privileges.\n");
return 1;
}
if (verbose) {
printf("Raised hard limit for NOFILE to %d.\n", (int) rl.rlim_max);
}
}
// Adjust soft limit if necessary
if (rl.rlim_cur < nofiles) {
rl.rlim_cur = nofiles;
if (setrlimit(RLIMIT_NOFILE, &rl) != 0) {
e = errno;
fprintf(stderr, "Failed to raise soft limit for NOFILE to %d: %s.\n",
(int) rl.rlim_cur, strerror(e));
return 1;
}
if (verbose) {
printf("Raised soft limit for NOFILE to %d.\n", (int) rl.rlim_cur);
}
}
if (cap_set_proc(privilege_dropped)) {
fprintf(stderr, "Failed to turn irrevocably drop privileges.\n");
return 1;
}
return 0;
}
Upvotes: 4