syscall messaging 3: Expand the 'header' that goes in front of the syscall
[dragonfly.git] / sys / kern / kern_resource.c
1 /*-
2  * Copyright (c) 1982, 1986, 1991, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  * (c) UNIX System Laboratories, Inc.
5  * All or some portions of this file are derived from material licensed
6  * to the University of California by American Telephone and Telegraph
7  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8  * the permission of UNIX System Laboratories, Inc.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *      This product includes software developed by the University of
21  *      California, Berkeley and its contributors.
22  * 4. Neither the name of the University nor the names of its contributors
23  *    may be used to endorse or promote products derived from this software
24  *    without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  *
38  *      @(#)kern_resource.c     8.5 (Berkeley) 1/21/94
39  * $FreeBSD: src/sys/kern/kern_resource.c,v 1.55.2.5 2001/11/03 01:41:08 ps Exp $
40  * $DragonFly: src/sys/kern/kern_resource.c,v 1.12 2003/07/30 00:19:14 dillon Exp $
41  */
42
43 #include "opt_compat.h"
44
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/sysproto.h>
48 #include <sys/file.h>
49 #include <sys/kernel.h>
50 #include <sys/resourcevar.h>
51 #include <sys/malloc.h>
52 #include <sys/proc.h>
53 #include <sys/time.h>
54
55 #include <vm/vm.h>
56 #include <vm/vm_param.h>
57 #include <sys/lock.h>
58 #include <vm/pmap.h>
59 #include <vm/vm_map.h>
60
61 static int donice __P((struct proc *chgp, int n));
62
63 static MALLOC_DEFINE(M_UIDINFO, "uidinfo", "uidinfo structures");
64 #define UIHASH(uid)     (&uihashtbl[(uid) & uihash])
65 static LIST_HEAD(uihashhead, uidinfo) *uihashtbl;
66 static u_long uihash;           /* size of hash table - 1 */
67
68 static struct uidinfo   *uicreate __P((uid_t uid));
69 static struct uidinfo   *uilookup __P((uid_t uid));
70
71 /*
72  * Resource controls and accounting.
73  */
74
75 int
76 getpriority(struct getpriority_args *uap)
77 {
78         struct proc *curp = curproc;
79         struct proc *p;
80         int low = PRIO_MAX + 1;
81
82         switch (uap->which) {
83         case PRIO_PROCESS:
84                 if (uap->who == 0)
85                         p = curp;
86                 else
87                         p = pfind(uap->who);
88                 if (p == 0)
89                         break;
90                 if (!PRISON_CHECK(curp->p_ucred, p->p_ucred))
91                         break;
92                 low = p->p_nice;
93                 break;
94
95         case PRIO_PGRP: 
96         {
97                 struct pgrp *pg;
98
99                 if (uap->who == 0)
100                         pg = curp->p_pgrp;
101                 else if ((pg = pgfind(uap->who)) == NULL)
102                         break;
103                 LIST_FOREACH(p, &pg->pg_members, p_pglist) {
104                         if ((PRISON_CHECK(curp->p_ucred, p->p_ucred) && p->p_nice < low))
105                                 low = p->p_nice;
106                 }
107                 break;
108         }
109         case PRIO_USER:
110                 if (uap->who == 0)
111                         uap->who = curp->p_ucred->cr_uid;
112                 LIST_FOREACH(p, &allproc, p_list)
113                         if (PRISON_CHECK(curp->p_ucred, p->p_ucred) &&
114                             p->p_ucred->cr_uid == uap->who &&
115                             p->p_nice < low)
116                                 low = p->p_nice;
117                 break;
118
119         default:
120                 return (EINVAL);
121         }
122         if (low == PRIO_MAX + 1)
123                 return (ESRCH);
124         uap->sysmsg_result = low;
125         return (0);
126 }
127
128 /* ARGSUSED */
129 int
130 setpriority(struct setpriority_args *uap)
131 {
132         struct proc *curp = curproc;
133         struct proc *p;
134         int found = 0, error = 0;
135
136         switch (uap->which) {
137
138         case PRIO_PROCESS:
139                 if (uap->who == 0)
140                         p = curp;
141                 else
142                         p = pfind(uap->who);
143                 if (p == 0)
144                         break;
145                 if (!PRISON_CHECK(curp->p_ucred, p->p_ucred))
146                         break;
147                 error = donice(p, uap->prio);
148                 found++;
149                 break;
150
151         case PRIO_PGRP: 
152         {
153                 struct pgrp *pg;
154
155                 if (uap->who == 0)
156                         pg = curp->p_pgrp;
157                 else if ((pg = pgfind(uap->who)) == NULL)
158                         break;
159                 LIST_FOREACH(p, &pg->pg_members, p_pglist) {
160                         if (PRISON_CHECK(curp->p_ucred, p->p_ucred)) {
161                                 error = donice(p, uap->prio);
162                                 found++;
163                         }
164                 }
165                 break;
166         }
167         case PRIO_USER:
168                 if (uap->who == 0)
169                         uap->who = curp->p_ucred->cr_uid;
170                 LIST_FOREACH(p, &allproc, p_list)
171                         if (p->p_ucred->cr_uid == uap->who &&
172                             PRISON_CHECK(curp->p_ucred, p->p_ucred)) {
173                                 error = donice(p, uap->prio);
174                                 found++;
175                         }
176                 break;
177
178         default:
179                 return (EINVAL);
180         }
181         if (found == 0)
182                 return (ESRCH);
183         return (error);
184 }
185
186 static int
187 donice(struct proc *chgp, int n)
188 {
189         struct proc *curp = curproc;
190         struct ucred *cr = curp->p_ucred;
191
192         if (cr->cr_uid && cr->cr_ruid &&
193             cr->cr_uid != chgp->p_ucred->cr_uid &&
194             cr->cr_ruid != chgp->p_ucred->cr_uid)
195                 return (EPERM);
196         if (n > PRIO_MAX)
197                 n = PRIO_MAX;
198         if (n < PRIO_MIN)
199                 n = PRIO_MIN;
200         if (n < chgp->p_nice && suser_cred(cr, 0))
201                 return (EACCES);
202         chgp->p_nice = n;
203         (void)resetpriority(chgp);
204         return (0);
205 }
206
207 /*
208  * Set realtime priority
209  */
210 /* ARGSUSED */
211 int
212 rtprio(struct rtprio_args *uap)
213 {
214         struct proc *curp = curproc;
215         struct proc *p;
216         struct ucred *cr = curp->p_ucred;
217         struct rtprio rtp;
218         int error;
219
220         error = copyin(uap->rtp, &rtp, sizeof(struct rtprio));
221         if (error)
222                 return (error);
223
224         if (uap->pid == 0)
225                 p = curp;
226         else
227                 p = pfind(uap->pid);
228
229         if (p == 0)
230                 return (ESRCH);
231
232         switch (uap->function) {
233         case RTP_LOOKUP:
234                 return (copyout(&p->p_rtprio, uap->rtp, sizeof(struct rtprio)));
235         case RTP_SET:
236                 if (cr->cr_uid && cr->cr_ruid &&
237                     cr->cr_uid != p->p_ucred->cr_uid &&
238                     cr->cr_ruid != p->p_ucred->cr_uid)
239                         return (EPERM);
240                 /* disallow setting rtprio in most cases if not superuser */
241                 if (suser_cred(cr, 0)) {
242                         /* can't set someone else's */
243                         if (uap->pid)
244                                 return (EPERM);
245                         /* can't set realtime priority */
246 /*
247  * Realtime priority has to be restricted for reasons which should be
248  * obvious. However, for idle priority, there is a potential for
249  * system deadlock if an idleprio process gains a lock on a resource
250  * that other processes need (and the idleprio process can't run
251  * due to a CPU-bound normal process). Fix me! XXX
252  */
253                         if (RTP_PRIO_IS_REALTIME(rtp.type))
254                                 return (EPERM);
255                 }
256                 switch (rtp.type) {
257 #ifdef RTP_PRIO_FIFO
258                 case RTP_PRIO_FIFO:
259 #endif
260                 case RTP_PRIO_REALTIME:
261                 case RTP_PRIO_NORMAL:
262                 case RTP_PRIO_IDLE:
263                         if (rtp.prio > RTP_PRIO_MAX)
264                                 return (EINVAL);
265                         p->p_rtprio = rtp;
266                         return (0);
267                 default:
268                         return (EINVAL);
269                 }
270
271         default:
272                 return (EINVAL);
273         }
274 }
275
276 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
277 /* ARGSUSED */
278 int
279 osetrlimit(struct osetrlimit_args *uap)
280 {
281         struct orlimit olim;
282         struct rlimit lim;
283         int error;
284
285         if ((error =
286             copyin((caddr_t)uap->rlp, (caddr_t)&olim, sizeof(struct orlimit))))
287                 return (error);
288         lim.rlim_cur = olim.rlim_cur;
289         lim.rlim_max = olim.rlim_max;
290         return (dosetrlimit(uap->which, &lim));
291 }
292
293 /* ARGSUSED */
294 int
295 ogetrlimit(struct ogetrlimit_args *uap)
296 {
297         struct proc *p = curproc;
298         struct orlimit olim;
299
300         if (uap->which >= RLIM_NLIMITS)
301                 return (EINVAL);
302         olim.rlim_cur = p->p_rlimit[uap->which].rlim_cur;
303         if (olim.rlim_cur == -1)
304                 olim.rlim_cur = 0x7fffffff;
305         olim.rlim_max = p->p_rlimit[uap->which].rlim_max;
306         if (olim.rlim_max == -1)
307                 olim.rlim_max = 0x7fffffff;
308         return (copyout((caddr_t)&olim, (caddr_t)uap->rlp, sizeof(olim)));
309 }
310 #endif /* COMPAT_43 || COMPAT_SUNOS */
311
312 /* ARGSUSED */
313 int
314 setrlimit(struct __setrlimit_args *uap)
315 {
316         struct rlimit alim;
317         int error;
318
319         if ((error =
320             copyin((caddr_t)uap->rlp, (caddr_t)&alim, sizeof (struct rlimit))))
321                 return (error);
322         return (dosetrlimit(uap->which, &alim));
323 }
324
325 int
326 dosetrlimit(u_int which, struct rlimit *limp)
327 {
328         struct proc *p = curproc;
329         struct rlimit *alimp;
330         int error;
331
332         if (which >= RLIM_NLIMITS)
333                 return (EINVAL);
334         alimp = &p->p_rlimit[which];
335
336         /*
337          * Preserve historical bugs by treating negative limits as unsigned.
338          */
339         if (limp->rlim_cur < 0)
340                 limp->rlim_cur = RLIM_INFINITY;
341         if (limp->rlim_max < 0)
342                 limp->rlim_max = RLIM_INFINITY;
343
344         if (limp->rlim_cur > alimp->rlim_max ||
345             limp->rlim_max > alimp->rlim_max)
346                 if ((error = suser_cred(p->p_ucred, PRISON_ROOT)))
347                         return (error);
348         if (limp->rlim_cur > limp->rlim_max)
349                 limp->rlim_cur = limp->rlim_max;
350         if (p->p_limit->p_refcnt > 1 &&
351             (p->p_limit->p_lflags & PL_SHAREMOD) == 0) {
352                 p->p_limit->p_refcnt--;
353                 p->p_limit = limcopy(p->p_limit);
354                 alimp = &p->p_rlimit[which];
355         }
356
357         switch (which) {
358
359         case RLIMIT_CPU:
360                 if (limp->rlim_cur > RLIM_INFINITY / (rlim_t)1000000)
361                         p->p_limit->p_cpulimit = RLIM_INFINITY;
362                 else
363                         p->p_limit->p_cpulimit = 
364                             (rlim_t)1000000 * limp->rlim_cur;
365                 break;
366         case RLIMIT_DATA:
367                 if (limp->rlim_cur > maxdsiz)
368                         limp->rlim_cur = maxdsiz;
369                 if (limp->rlim_max > maxdsiz)
370                         limp->rlim_max = maxdsiz;
371                 break;
372
373         case RLIMIT_STACK:
374                 if (limp->rlim_cur > maxssiz)
375                         limp->rlim_cur = maxssiz;
376                 if (limp->rlim_max > maxssiz)
377                         limp->rlim_max = maxssiz;
378                 /*
379                  * Stack is allocated to the max at exec time with only
380                  * "rlim_cur" bytes accessible.  If stack limit is going
381                  * up make more accessible, if going down make inaccessible.
382                  */
383                 if (limp->rlim_cur != alimp->rlim_cur) {
384                         vm_offset_t addr;
385                         vm_size_t size;
386                         vm_prot_t prot;
387
388                         if (limp->rlim_cur > alimp->rlim_cur) {
389                                 prot = VM_PROT_ALL;
390                                 size = limp->rlim_cur - alimp->rlim_cur;
391                                 addr = USRSTACK - limp->rlim_cur;
392                         } else {
393                                 prot = VM_PROT_NONE;
394                                 size = alimp->rlim_cur - limp->rlim_cur;
395                                 addr = USRSTACK - alimp->rlim_cur;
396                         }
397                         addr = trunc_page(addr);
398                         size = round_page(size);
399                         (void) vm_map_protect(&p->p_vmspace->vm_map,
400                                               addr, addr+size, prot, FALSE);
401                 }
402                 break;
403
404         case RLIMIT_NOFILE:
405                 if (limp->rlim_cur > maxfilesperproc)
406                         limp->rlim_cur = maxfilesperproc;
407                 if (limp->rlim_max > maxfilesperproc)
408                         limp->rlim_max = maxfilesperproc;
409                 break;
410
411         case RLIMIT_NPROC:
412                 if (limp->rlim_cur > maxprocperuid)
413                         limp->rlim_cur = maxprocperuid;
414                 if (limp->rlim_max > maxprocperuid)
415                         limp->rlim_max = maxprocperuid;
416                 if (limp->rlim_cur < 1)
417                         limp->rlim_cur = 1;
418                 if (limp->rlim_max < 1)
419                         limp->rlim_max = 1;
420                 break;
421         }
422         *alimp = *limp;
423         return (0);
424 }
425
426 /* ARGSUSED */
427 int
428 getrlimit(struct __getrlimit_args *uap)
429 {
430         struct proc *p = curproc;
431
432         if (uap->which >= RLIM_NLIMITS)
433                 return (EINVAL);
434         return (copyout((caddr_t)&p->p_rlimit[uap->which], (caddr_t)uap->rlp,
435             sizeof (struct rlimit)));
436 }
437
438 /*
439  * Transform the running time and tick information in proc p into user,
440  * system, and interrupt time usage.
441  *
442  * Since we are limited to statclock tick granularity this is a statisical
443  * calculation which will be correct over the long haul, but should not be
444  * expected to measure fine grained deltas.
445  */
446 void
447 calcru(p, up, sp, ip)
448         struct proc *p;
449         struct timeval *up;
450         struct timeval *sp;
451         struct timeval *ip;
452 {
453         struct thread *td = p->p_thread;
454         int s;
455
456         /*
457          * Calculate at the statclock level.  YYY if the thread is owned by
458          * another cpu we need to forward the request to the other cpu, or
459          * have a token to interlock the information.
460          */
461         s = splstatclock();
462         up->tv_sec = td->td_uticks / 1000000;
463         up->tv_usec = td->td_uticks % 1000000;
464         sp->tv_sec = td->td_sticks / 1000000;
465         sp->tv_usec = td->td_sticks % 1000000;
466         if (ip != NULL) {
467                 ip->tv_sec = td->td_iticks / 1000000;
468                 ip->tv_usec = td->td_iticks % 1000000;
469         }
470         splx(s);
471 }
472
473 /* ARGSUSED */
474 int
475 getrusage(struct getrusage_args *uap)
476 {
477         struct proc *p = curproc;
478         struct rusage *rup;
479
480         switch (uap->who) {
481
482         case RUSAGE_SELF:
483                 rup = &p->p_stats->p_ru;
484                 calcru(p, &rup->ru_utime, &rup->ru_stime, NULL);
485                 break;
486
487         case RUSAGE_CHILDREN:
488                 rup = &p->p_stats->p_cru;
489                 break;
490
491         default:
492                 return (EINVAL);
493         }
494         return (copyout((caddr_t)rup, (caddr_t)uap->rusage,
495             sizeof (struct rusage)));
496 }
497
498 void
499 ruadd(ru, ru2)
500         struct rusage *ru, *ru2;
501 {
502         long *ip, *ip2;
503         int i;
504
505         timevaladd(&ru->ru_utime, &ru2->ru_utime);
506         timevaladd(&ru->ru_stime, &ru2->ru_stime);
507         if (ru->ru_maxrss < ru2->ru_maxrss)
508                 ru->ru_maxrss = ru2->ru_maxrss;
509         ip = &ru->ru_first; ip2 = &ru2->ru_first;
510         for (i = &ru->ru_last - &ru->ru_first; i >= 0; i--)
511                 *ip++ += *ip2++;
512 }
513
514 /*
515  * Make a copy of the plimit structure.
516  * We share these structures copy-on-write after fork,
517  * and copy when a limit is changed.
518  */
519 struct plimit *
520 limcopy(lim)
521         struct plimit *lim;
522 {
523         struct plimit *copy;
524
525         MALLOC(copy, struct plimit *, sizeof(struct plimit),
526             M_SUBPROC, M_WAITOK);
527         bcopy(lim->pl_rlimit, copy->pl_rlimit, sizeof(struct plimit));
528         copy->p_lflags = 0;
529         copy->p_refcnt = 1;
530         return (copy);
531 }
532
533 /*
534  * Find the uidinfo structure for a uid.  This structure is used to
535  * track the total resource consumption (process count, socket buffer
536  * size, etc.) for the uid and impose limits.
537  */
538 void
539 uihashinit()
540 {
541         uihashtbl = hashinit(maxproc / 16, M_UIDINFO, &uihash);
542 }
543
544 static struct uidinfo *
545 uilookup(uid)
546         uid_t uid;
547 {
548         struct  uihashhead *uipp;
549         struct  uidinfo *uip;
550
551         uipp = UIHASH(uid);
552         LIST_FOREACH(uip, uipp, ui_hash)
553                 if (uip->ui_uid == uid)
554                         break;
555
556         return (uip);
557 }
558
559 static struct uidinfo *
560 uicreate(uid)
561         uid_t uid;
562 {
563         struct  uidinfo *uip, *norace;
564
565         MALLOC(uip, struct uidinfo *, sizeof(*uip), M_UIDINFO, M_NOWAIT);
566         if (uip == NULL) {
567                 MALLOC(uip, struct uidinfo *, sizeof(*uip), M_UIDINFO, M_WAITOK);
568                 /*
569                  * if we M_WAITOK we must look afterwards or risk
570                  * redundant entries
571                  */
572                 norace = uilookup(uid);
573                 if (norace != NULL) {
574                         FREE(uip, M_UIDINFO);
575                         return (norace);
576                 }
577         }
578         LIST_INSERT_HEAD(UIHASH(uid), uip, ui_hash);
579         uip->ui_uid = uid;
580         uip->ui_proccnt = 0;
581         uip->ui_sbsize = 0;
582         uip->ui_ref = 0;
583         return (uip);
584 }
585
586 struct uidinfo *
587 uifind(uid)
588         uid_t uid;
589 {
590         struct  uidinfo *uip;
591
592         uip = uilookup(uid);
593         if (uip == NULL)
594                 uip = uicreate(uid);
595         uip->ui_ref++;
596         return (uip);
597 }
598
599 int
600 uifree(uip)
601         struct  uidinfo *uip;
602 {
603
604         if (--uip->ui_ref == 0) {
605                 if (uip->ui_sbsize != 0)
606                         /* XXX no %qd in kernel.  Truncate. */
607                         printf("freeing uidinfo: uid = %d, sbsize = %ld\n",
608                             uip->ui_uid, (long)uip->ui_sbsize);
609                 if (uip->ui_proccnt != 0)
610                         printf("freeing uidinfo: uid = %d, proccnt = %ld\n",
611                             uip->ui_uid, uip->ui_proccnt);
612                 LIST_REMOVE(uip, ui_hash);
613                 FREE(uip, M_UIDINFO);
614                 return (1);
615         }
616         return (0);
617 }
618
619 /*
620  * Change the count associated with number of processes
621  * a given user is using.  When 'max' is 0, don't enforce a limit
622  */
623 int
624 chgproccnt(uip, diff, max)
625         struct  uidinfo *uip;
626         int     diff;
627         int     max;
628 {
629         /* don't allow them to exceed max, but allow subtraction */
630         if (diff > 0 && uip->ui_proccnt + diff > max && max != 0)
631                 return (0);
632         uip->ui_proccnt += diff;
633         if (uip->ui_proccnt < 0)
634                 printf("negative proccnt for uid = %d\n", uip->ui_uid);
635         return (1);
636 }
637
638 /*
639  * Change the total socket buffer size a user has used.
640  */
641 int
642 chgsbsize(uip, hiwat, to, max)
643         struct  uidinfo *uip;
644         u_long *hiwat;
645         u_long  to;
646         rlim_t  max;
647 {
648         rlim_t new;
649         int s;
650
651         s = splnet();
652         new = uip->ui_sbsize + to - *hiwat;
653         /* don't allow them to exceed max, but allow subtraction */
654         if (to > *hiwat && new > max) {
655                 splx(s);
656                 return (0);
657         }
658         uip->ui_sbsize = new;
659         *hiwat = to;
660         if (uip->ui_sbsize < 0)
661                 printf("negative sbsize for uid = %d\n", uip->ui_uid);
662         splx(s);
663         return (1);
664 }