Commit e43379f10b42194b8a6e1de342cfb44463c0f6da
Committed by
Linus Torvalds
1 parent
9fc1427a01
Exists in
master
and in
4 other branches
[PATCH] nice and rt-prio rlimits
Add a pair of rlimits for allowing non-root tasks to raise nice and rt priorities. Defaults to traditional behavior. Originally written by Chris Wright. The patch implements a simple rlimit ceiling for the RT (and nice) priorities a task can set. The rlimit defaults to 0, meaning no change in behavior by default. A value of 50 means RT priority levels 1-50 are allowed. A value of 100 means all 99 privilege levels from 1 to 99 are allowed. CAP_SYS_NICE is blanket permission. (akpm: see http://www.uwsg.iu.edu/hypermail/linux/kernel/0503.1/1921.html for tips on integrating this with PAM). Signed-off-by: Matt Mackall <mpm@selenic.com> Acked-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Showing 4 changed files with 27 additions and 8 deletions Side-by-side Diff
include/asm-generic/resource.h
... | ... | @@ -41,8 +41,11 @@ |
41 | 41 | #define RLIMIT_LOCKS 10 /* maximum file locks held */ |
42 | 42 | #define RLIMIT_SIGPENDING 11 /* max number of pending signals */ |
43 | 43 | #define RLIMIT_MSGQUEUE 12 /* maximum bytes in POSIX mqueues */ |
44 | +#define RLIMIT_NICE 13 /* max nice prio allowed to raise to | |
45 | + 0-39 for nice level 19 .. -20 */ | |
46 | +#define RLIMIT_RTPRIO 14 /* maximum realtime priority */ | |
44 | 47 | |
45 | -#define RLIM_NLIMITS 13 | |
48 | +#define RLIM_NLIMITS 15 | |
46 | 49 | |
47 | 50 | /* |
48 | 51 | * SuS says limits have to be unsigned. |
... | ... | @@ -81,6 +84,8 @@ |
81 | 84 | [RLIMIT_LOCKS] = { RLIM_INFINITY, RLIM_INFINITY }, \ |
82 | 85 | [RLIMIT_SIGPENDING] = { 0, 0 }, \ |
83 | 86 | [RLIMIT_MSGQUEUE] = { MQ_BYTES_MAX, MQ_BYTES_MAX }, \ |
87 | + [RLIMIT_NICE] = { 0, 0 }, \ | |
88 | + [RLIMIT_RTPRIO] = { 0, 0 }, \ | |
84 | 89 | } |
85 | 90 | |
86 | 91 | #endif /* __KERNEL__ */ |
include/linux/sched.h
... | ... | @@ -845,6 +845,7 @@ |
845 | 845 | extern void set_user_nice(task_t *p, long nice); |
846 | 846 | extern int task_prio(const task_t *p); |
847 | 847 | extern int task_nice(const task_t *p); |
848 | +extern int can_nice(const task_t *p, const int nice); | |
848 | 849 | extern int task_curr(const task_t *p); |
849 | 850 | extern int idle_cpu(int cpu); |
850 | 851 | extern int sched_setscheduler(struct task_struct *, int, struct sched_param *); |
kernel/sched.c
... | ... | @@ -3223,6 +3223,19 @@ |
3223 | 3223 | |
3224 | 3224 | EXPORT_SYMBOL(set_user_nice); |
3225 | 3225 | |
3226 | +/* | |
3227 | + * can_nice - check if a task can reduce its nice value | |
3228 | + * @p: task | |
3229 | + * @nice: nice value | |
3230 | + */ | |
3231 | +int can_nice(const task_t *p, const int nice) | |
3232 | +{ | |
3233 | + /* convert nice value [19,-20] to rlimit style value [0,39] */ | |
3234 | + int nice_rlim = 19 - nice; | |
3235 | + return (nice_rlim <= p->signal->rlim[RLIMIT_NICE].rlim_cur || | |
3236 | + capable(CAP_SYS_NICE)); | |
3237 | +} | |
3238 | + | |
3226 | 3239 | #ifdef __ARCH_WANT_SYS_NICE |
3227 | 3240 | |
3228 | 3241 | /* |
... | ... | @@ -3242,12 +3255,8 @@ |
3242 | 3255 | * We don't have to worry. Conceptually one call occurs first |
3243 | 3256 | * and we have a single winner. |
3244 | 3257 | */ |
3245 | - if (increment < 0) { | |
3246 | - if (!capable(CAP_SYS_NICE)) | |
3247 | - return -EPERM; | |
3248 | - if (increment < -40) | |
3249 | - increment = -40; | |
3250 | - } | |
3258 | + if (increment < -40) | |
3259 | + increment = -40; | |
3251 | 3260 | if (increment > 40) |
3252 | 3261 | increment = 40; |
3253 | 3262 | |
... | ... | @@ -3257,6 +3266,9 @@ |
3257 | 3266 | if (nice > 19) |
3258 | 3267 | nice = 19; |
3259 | 3268 | |
3269 | + if (increment < 0 && !can_nice(current, nice)) | |
3270 | + return -EPERM; | |
3271 | + | |
3260 | 3272 | retval = security_task_setnice(current, nice); |
3261 | 3273 | if (retval) |
3262 | 3274 | return retval; |
... | ... | @@ -3372,6 +3384,7 @@ |
3372 | 3384 | return -EINVAL; |
3373 | 3385 | |
3374 | 3386 | if ((policy == SCHED_FIFO || policy == SCHED_RR) && |
3387 | + param->sched_priority > p->signal->rlim[RLIMIT_RTPRIO].rlim_cur && | |
3375 | 3388 | !capable(CAP_SYS_NICE)) |
3376 | 3389 | return -EPERM; |
3377 | 3390 | if ((current->euid != p->euid) && (current->euid != p->uid) && |
kernel/sys.c