Don't allow others to run uuconv
[unix-history] / sys / procfs / procfs_vnops.c
CommitLineData
317350b1
DG
1/*
2 * Copyright (c) 1993 Paul Kranenburg
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by Paul Kranenburg.
16 * 4. The name of the author may not be used to endorse or promote products
17 * derived from this software withough specific prior written permission
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
22c84afa 30 * $Id: procfs_vnops.c,v 1.6 1994/01/31 04:19:20 davidg Exp $
317350b1
DG
31 */
32
33/*
34 * PROCFS vnode interface routines
35 */
36
37#include "param.h"
38#include "systm.h"
39#include "time.h"
40#include "kernel.h"
41#include "ioctl.h"
42#include "file.h"
43#include "proc.h"
44#include "buf.h"
45#include "vnode.h"
46#include "namei.h"
47#include "resourcevar.h"
48#include "vm/vm.h"
22c84afa 49#include "vm/vm_page.h"
317350b1
DG
50#include "kinfo.h"
51#include "kinfo_proc.h"
52
fde1aeb2 53#include "sys/procfs.h"
317350b1
DG
54#include "pfsnode.h"
55
56#include "machine/vmparam.h"
57
58/*
59 * procfs vnode operations.
60 */
61struct vnodeops pfs_vnodeops = {
62 pfs_lookup, /* lookup */
63 pfs_create, /* create */
64 pfs_mknod, /* mknod */
65 pfs_open, /* open */
66 pfs_close, /* close */
67 pfs_access, /* access */
68 pfs_getattr, /* getattr */
69 pfs_setattr, /* setattr */
70 pfs_read, /* read */
71 pfs_write, /* write */
72 pfs_ioctl, /* ioctl */
73 pfs_select, /* select */
74 pfs_mmap, /* mmap */
75 pfs_fsync, /* fsync */
76 pfs_seek, /* seek */
77 pfs_remove, /* remove */
78 pfs_link, /* link */
79 pfs_rename, /* rename */
80 pfs_mkdir, /* mkdir */
81 pfs_rmdir, /* rmdir */
82 pfs_symlink, /* symlink */
83 pfs_readdir, /* readdir */
84 pfs_readlink, /* readlink */
85 pfs_abortop, /* abortop */
86 pfs_inactive, /* inactive */
87 pfs_reclaim, /* reclaim */
88 pfs_lock, /* lock */
89 pfs_unlock, /* unlock */
90 pfs_bmap, /* bmap */
91 pfs_strategy, /* strategy */
92 pfs_print, /* print */
93 pfs_islocked, /* islocked */
94 pfs_advlock, /* advlock */
95};
96
97/*
98 * Vnode Operations.
99 *
100 */
101/* ARGSUSED */
102int
103pfs_open(vp, mode, cred, p)
104 register struct vnode *vp;
105 int mode;
106 struct ucred *cred;
107 struct proc *p;
108{
109 struct pfsnode *pfsp = VTOPFS(vp);
110 struct proc *procp;
111
112#ifdef DEBUG
113 if (pfs_debug)
114 printf("pfs_open: vp 0x%x, proc %d\n", vp, p->p_pid);
115#endif
116
117 if ( (procp = (pfsp->pfs_pid?pfind(pfsp->pfs_pid):&proc0)) == NULL)
118 return ESRCH;
119
120 if ( (pfsp->pfs_flags & FWRITE) && (mode & O_EXCL) ||
121 (pfsp->pfs_flags & O_EXCL) && (mode & FWRITE) )
122 return EBUSY;
123
124
125 if (mode & FWRITE)
126 pfsp->pfs_flags = (mode & (FWRITE|O_EXCL));
127
317350b1
DG
128 procp->p_vmspace->vm_refcnt++;
129 pfsp->pfs_vs = procp->p_vmspace;
317350b1
DG
130 return 0;
131}
132
133/*
134 * /proc filesystem close routine
135 */
136/* ARGSUSED */
137int
138pfs_close(vp, flag, cred, p)
139 register struct vnode *vp;
140 int flag;
141 struct ucred *cred;
142 struct proc *p;
143{
144 struct pfsnode *pfsp = VTOPFS(vp);
145
146#ifdef DEBUG
147 if (pfs_debug)
148 printf("pfs_close: vp 0x%x proc %d\n", vp, p->p_pid);
149#endif
150 if ((flag & FWRITE) && (pfsp->pfs_flags & O_EXCL))
151 pfsp->pfs_flags &= ~(FWRITE|O_EXCL);
152
317350b1 153 vmspace_free(pfsp->pfs_vs);
317350b1
DG
154 return (0);
155}
156
157/*
158 * Ioctl operation.
159 */
160/* ARGSUSED */
161int
162pfs_ioctl(vp, com, data, fflag, cred, p)
163 struct vnode *vp;
164 int com;
165 caddr_t data;
166 int fflag;
167 struct ucred *cred;
168 struct proc *p;
169{
170 int error = 0;
171 struct proc *procp;
172 struct pfsnode *pfsp = VTOPFS(vp);
173
174 procp = pfsp->pfs_pid?pfind(pfsp->pfs_pid):&proc0;
175 if (!procp)
176 return ESRCH;
177
178 switch (com) {
179
180 case PIOCGPINFO: {
181 int copysize = sizeof(struct kinfo_proc), needed;
182 kinfo_doproc(KINFO_PROC_PID, data, &copysize,
183 pfsp->pfs_pid, &needed);
184 break;
185 }
186
187#ifdef notyet /* Changes to proc.h needed */
188 case PIOCGSIGSET:
189 procp->p_psigset = *(sigset_t *)data;
190 break;
191
192 case PIOCSSIGSET:
193 *(sigset_t *)data = procp->p_psigset;
194 break;
195
196 case PIOCGFLTSET:
197 procp->p_pfltset = *(sigflt_t *)data;
198 break;
199
200 case PIOCSFLTSET:
201 *(fltset_t *)data = procp->p_pfltset;
202 break;
203#endif
204
205 case PIOCGMAPFD:
206 error = pfs_vmfd(procp, pfsp, (struct vmfd *)data, p);
207 break;
208
209 case PIOCGNMAP:
210 *(int *)data = pfs_vm_nentries(procp, pfsp);
211 break;
212
213 case PIOCGMAP:
214 error = pfs_vmmap(procp, pfsp, *(struct procmap *)data);
215 break;
216
22c84afa
DG
217 case PIOCGNVMINFO:
218 *(int *)data = pfs_vminfo_nentries(procp, pfsp);
219 break;
220
221 case PIOCGVMINFO:
222 error = pfs_vminfo(procp, pfsp, *(struct procvminfo *)data);
223 break;
317350b1
DG
224 default:
225 error = EIO;
226 break;
227 }
228 return error;
229}
230
231/*
232 * Pass I/O requests to the memory filesystem process.
233 */
234int
235pfs_strategy(bp)
236 register struct buf *bp;
237{
238 struct vnode *vp;
239 struct proc *p = curproc; /* XXX */
240
241 return (0);
242}
243
244/*
245 * This is a noop, simply returning what one has been given.
246 */
247int
248pfs_bmap(vp, bn, vpp, bnp)
249 struct vnode *vp;
250 daddr_t bn;
251 struct vnode **vpp;
252 daddr_t *bnp;
253{
254
255 if (vpp != NULL)
256 *vpp = vp;
257 if (bnp != NULL)
258 *bnp = bn;
259 return (0);
260}
261
262/*
263 * /proc filesystem inactive routine
264 */
265/* ARGSUSED */
266int
267pfs_inactive(vp, p)
268 struct vnode *vp;
269 struct proc *p;
270{
271 struct pfsnode *pfsp = VTOPFS(vp);
272
317350b1 273 if ((pfsp->pfs_pid?pfind(pfsp->pfs_pid):&proc0) == NULL
3ae4ee21 274 && vp->v_usecount == 0)
317350b1
DG
275 vgone(vp);
276
277 return 0;
278}
279
280/*
281 * /proc filesystem reclaim routine
282 */
283/* ARGSUSED */
284int
285pfs_reclaim(vp)
286 struct vnode *vp;
287{
288 struct pfsnode **pp, *pfsp = VTOPFS(vp);
289
290 for (pp = &pfshead; *pp; pp = &(*pp)->pfs_next) {
291 if (*pp == pfsp) {
292 *pp = pfsp->pfs_next;
293 break;
294 }
295 }
296 return 0;
297}
298
299/*
300 * Print out the contents of an pfsnode.
301 */
302void
303pfs_print(vp)
304 struct vnode *vp;
305{
306 struct pfsnode *pfsp = VTOPFS(vp);
307
308 printf("tag VT_PROCFS, pid %d, uid %d, gid %d, mode %x, flags %x\n",
309 pfsp->pfs_pid,
310 pfsp->pfs_uid, pfsp->pfs_gid,
311 pfsp->pfs_mode, pfsp->pfs_flags);
312
313 return;
314}
315
316/*
317 * /proc bad operation
318 */
319int
320pfs_badop()
321{
322 printf("pfs_badop called\n");
323 return EIO;
324}
325
326/*
327 * Make up some attributes for a process file
328 */
329int
330pfs_getattr (vp, vap, cred, p)
331 struct vnode *vp;
332 struct vattr *vap;
333 struct ucred *cred;
334 struct proc *p;
335{
336 struct pfsnode *pfsp = VTOPFS(vp);
337 struct proc *procp;
338
339 VATTR_NULL(vap);
340 vap->va_type = vp->v_type;
341 vap->va_flags = pfsp->pfs_vflags;
342
343 if (vp->v_flag & VROOT) {
4813100e 344 vap->va_mode = 0750; /* /proc = rwxr-x--- */
317350b1
DG
345 vap->va_nlink = 2;
346 vap->va_size =
347 roundup((2+nprocs)*sizeof(struct pfsdent), DIRBLKSIZ);
348 vap->va_size_rsv = 0;
349 vap->va_uid = 0;
4813100e 350 vap->va_gid = 2; /* XXX group kmem */
317350b1
DG
351 vap->va_bytes = 0;
352 vap->va_atime = vap->va_mtime = vap->va_ctime = time; /*XXX*/
353 vap->va_rdev = makedev(255, 255);
354 return 0;
355 }
356
357
358 vap->va_rdev = makedev(255, pfsp->pfs_pid);
4813100e 359 vap->va_mode = 0644;
317350b1
DG
360 procp = pfsp->pfs_pid?pfind(pfsp->pfs_pid):&proc0;
361 if (!procp)
362 return ESRCH;
363
364 vap->va_nlink = 1;
365 vap->va_size = ctob( procp->p_vmspace->vm_tsize +
366 procp->p_vmspace->vm_dsize +
367 procp->p_vmspace->vm_ssize);
368 vap->va_bytes = 0;
369 vap->va_size_rsv = 0;
a200ca2b 370 vap->va_blocksize = PAGE_SIZE;
317350b1
DG
371 vap->va_uid = procp->p_ucred->cr_uid;
372 vap->va_gid = procp->p_ucred->cr_gid;
373 if (vap->va_uid != procp->p_cred->p_ruid)
374 vap->va_mode |= VSUID;
375 if (vap->va_gid != procp->p_cred->p_rgid)
376 vap->va_mode |= VSGID;
377 if (procp->p_flag & SLOAD) {
378 vap->va_atime = vap->va_mtime = vap->va_ctime =
379 procp->p_stats->p_start;
380 }
381
382 return 0;
383}
384
385/*
386 * Set some attributes for a process file
387 */
388int
389pfs_setattr (vp, vap, cred, p)
390 struct vnode *vp;
391 struct vattr *vap;
392 struct ucred *cred;
393 struct proc *p;
394{
395 struct pfsnode *pfsp = VTOPFS(vp);
396 struct proc *procp;
397 int error = 0;
398
399 procp = pfsp->pfs_pid?pfind(pfsp->pfs_pid):&proc0;
400 if (!procp)
401 return ESRCH;
402
403 /*
404 * Check for unsetable attributes.
405 */
406 if ((vap->va_type != VNON) || (vap->va_nlink != (short)VNOVAL) ||
407 (vap->va_fsid != (long)VNOVAL) ||
408 (vap->va_fileid != (long)VNOVAL) ||
409 (vap->va_blocksize != (long)VNOVAL) ||
410 (vap->va_rdev != (dev_t)VNOVAL) ||
411 ((int)vap->va_bytes != (u_long)VNOVAL) ||
412 ((int)vap->va_bytes_rsv != (u_long)VNOVAL) ||
413 ((int)vap->va_size != (u_long)VNOVAL) ||
414 ((int)vap->va_size_rsv != (u_long)VNOVAL) ||
415 (vap->va_gen != (long)VNOVAL) ||
416 ((int)vap->va_atime.tv_sec != (u_long)VNOVAL) ||
417 ((int)vap->va_mtime.tv_sec != (u_long)VNOVAL) ||
418 ((int)vap->va_ctime.tv_sec != (u_long)VNOVAL) ||
419 (( (vap->va_uid != (uid_t)VNOVAL) ||
420 (vap->va_gid != (gid_t)VNOVAL)) && !(vp->v_flag & VROOT)) ) {
421 return (EINVAL);
422 }
423
424 /* set mode bits, only rwx bits are modified */
425 if (vap->va_mode != (u_short)VNOVAL) {
426 if (cred->cr_uid != pfsp->pfs_uid &&
427 (error = suser(cred, &p->p_acflag)))
428 return (error);
429 pfsp->pfs_mode = vap->va_mode & 0777;
430 }
431
432 /* For now, only allow to change ownership of "/proc" itself */
433 if ((vp->v_flag & VROOT) && vap->va_uid != (uid_t)VNOVAL) {
434 if ((error = suser(cred, &p->p_acflag)))
435 return (error);
436 pfsp->pfs_uid = vap->va_uid;
437 }
438
439 if ((vp->v_flag & VROOT) && vap->va_gid != (gid_t)VNOVAL) {
440 if ((cred->cr_uid != pfsp->pfs_uid ||
441 !groupmember(vap->va_gid, cred)) &&
442 (error = suser(cred, &p->p_acflag)))
443 return error;
444
445 pfsp->pfs_gid = vap->va_gid;
446 }
447
448 /* chflags() */
449 if (vap->va_flags != (u_long)VNOVAL) {
450 if (cred->cr_uid != pfsp->pfs_uid &&
451 (error = suser(cred, &p->p_acflag)))
452 return (error);
453 if (cred->cr_uid == 0) {
454 pfsp->pfs_vflags = vap->va_flags;
455 } else {
fde1aeb2 456 pfsp->pfs_vflags &= 0xffff0000ul;
317350b1
DG
457 pfsp->pfs_vflags |= (vap->va_flags & 0xffff);
458 }
459 }
460 return 0;
461}
462
463int
464pfs_access (vp, mode, cred, p)
465 struct vnode *vp;
466 int mode;
467 struct ucred *cred;
468 struct proc *p;
469{
470 register struct vattr *vap;
471 register gid_t *gp;
472 struct vattr vattr;
473 register int i;
474 int error;
475
476 /*
477 * If you're the super-user,
478 * you always get access.
479 */
480 if (cred->cr_uid == (uid_t)0)
481 return (0);
482 vap = &vattr;
483 if (error = pfs_getattr(vp, vap, cred, p))
484 return (error);
485 /*
486 * Access check is based on only one of owner, group, public.
487 * If not owner, then check group. If not a member of the
488 * group, then check public access.
489 */
490 if (cred->cr_uid != vap->va_uid) {
491 mode >>= 3;
492 gp = cred->cr_groups;
493 for (i = 0; i < cred->cr_ngroups; i++, gp++)
494 if (vap->va_gid == *gp)
495 goto found;
496 mode >>= 3;
497found:
498 ;
499 }
500 if ((vap->va_mode & mode) != 0)
501 return (0);
502 return (EACCES);
503}
504
505/*
506 * /proc lookup
507 */
508int
509pfs_lookup(vp, ndp, p)
510 register struct vnode *vp;
511 register struct nameidata *ndp;
512 struct proc *p;
513{
514 int lockparent, wantparent, flag, error = 0;
515 pid_t pid;
516 struct vnode *nvp;
517 struct pfsnode *pfsp;
518 struct proc *procp;
519
520#ifdef DEBUG
521 if (pfs_debug)
522 printf("pfs_lookup: vp 0x%x name %s proc %d\n",
523 vp, ndp->ni_ptr, p->p_pid);
524#endif
525
526 ndp->ni_dvp = vp;
527 ndp->ni_vp = NULL;
528 if (vp->v_type != VDIR)
529 return (ENOTDIR);
530
531 lockparent = ndp->ni_nameiop & LOCKPARENT;
532 flag = ndp->ni_nameiop & OPMASK;
533 wantparent = ndp->ni_nameiop & (LOCKPARENT|WANTPARENT);
534 if (flag != LOOKUP)
535 return EACCES;
536 if (ndp->ni_isdotdot) {
537 /* Should not happen */
538 printf("pfs_lookup: vp 0x%x: dotdot\n", vp);
539 return EIO;
540 }
541 if (ndp->ni_namelen == 1 && *ndp->ni_ptr == '.') {
542 VREF(vp);
543 ndp->ni_vp = vp;
544 return 0;
545 }
546
547 pid = (pid_t)atoi(ndp->ni_ptr, ndp->ni_namelen);
548 if (pid == (pid_t)-1)
549 return ENOENT;
550
551 if ((procp = pid?pfind(pid):&proc0) == NULL)
552 return ENOENT;
553
3ae4ee21 554loop:
317350b1
DG
555 /* Search pfs node list first */
556 for (pfsp = pfshead; pfsp != NULL; pfsp = pfsp->pfs_next) {
557 if (pfsp->pfs_pid == pid)
558 break;
559 }
560
561 if (pfsp == NULL) {
562 struct pfsnode **pp;
563 error = getnewvnode(VT_PROCFS, vp->v_mount, &pfs_vnodeops, &nvp);
564 if (error)
565 return error;
566
567 nvp->v_type = VPROC;
568 pfsp = VTOPFS(nvp);
569 pfsp->pfs_next = NULL;
570 pfsp->pfs_pid = pid;
571 pfsp->pfs_vnode = nvp;
572 pfsp->pfs_flags = 0;
573 pfsp->pfs_vflags = 0;
574 pfsp->pfs_uid = procp->p_ucred->cr_uid;
575 pfsp->pfs_gid = procp->p_ucred->cr_gid;
576 pfsp->pfs_mode = 0700; /* Initial access bits */
577
578 /* Append to pfs node list */
579 pfsp->pfs_next = pfshead;
580 pfshead = pfsp;
581
3ae4ee21
DG
582 } else {
583 if (vget(pfsp->pfs_vnode))
584 goto loop;
585 VOP_UNLOCK(pfsp->pfs_vnode);
317350b1
DG
586 }
587 ndp->ni_vp = pfsp->pfs_vnode;
588
589 return (error);
590}
591
592int
593pfs_readdir(vp, uio, cred, eofflagp)
594 struct vnode *vp;
595 register struct uio *uio;
596 struct ucred *cred;
597 int *eofflagp;
598{
599 int error = 0;
600 int count, lost, pcnt, skipcnt, doingzomb = 0;
601 struct proc *p;
602 struct pfsdent dent;
603
604#ifdef DEBUG
605 if (pfs_debug)
606 printf("pfs_readdir: vp 0x%x proc %d\n",
607 vp, uio->uio_procp->p_pid);
608#endif
609 count = uio->uio_resid;
610 count &= ~(DIRBLKSIZ - 1);
611 lost = uio->uio_resid - count;
612 if (count < DIRBLKSIZ || (uio->uio_offset & (DIRBLKSIZ -1)))
613 return (EINVAL);
614 uio->uio_resid = count;
615 uio->uio_iov->iov_len = count;
616 *eofflagp = 1;
617 skipcnt = uio->uio_offset / sizeof(struct pfsdent);
618
619 count = 0;
620 if (skipcnt == 0) {
621 /* Fake "." and ".." entries? */
622#if 0
623 dent.d_fileno = 2; /* XXX - Filesystem root */
624 dent.d_reclen = sizeof(struct pfsdent);
625
626 dent.d_namlen = 1;
627 dent.d_nam[0] = '.';
628 dent.d_nam[1] = '\0';
629 error = uiomove((char *)&dent, sizeof(struct pfsdent) , uio);
630 if (error)
631 return error;
632
633 dent.d_fileno = 2;
634 dent.d_namlen = 2;
635 dent.d_nam[1] = '.';
636 dent.d_nam[2] = '\0';
637 error = uiomove((char *)&dent, sizeof(struct pfsdent) , uio);
638 if (error)
639 return error;
640#endif
641 count += 2*dent.d_reclen;
642 }
643
644 p = (struct proc *)allproc;
645 for (pcnt = 0; p && uio->uio_resid; pcnt++) {
646 if (pcnt < skipcnt) {
647 p = p->p_nxt;
648 if (p == NULL && doingzomb == 0) {
649 doingzomb = 1;
650 p = zombproc;
651 }
652 continue;
653 }
654 *eofflagp = 0;
655
656 /* "inode" is process slot (actually position on list) */
657 dent.d_fileno = (unsigned long)(pcnt+1);
658 dent.d_namlen = itos((unsigned int)p->p_pid, dent.d_nam);
659 dent.d_nam[dent.d_namlen] = '\0';
660
661 p = p->p_nxt;
662 if (p == NULL && doingzomb == 0) {
663 doingzomb = 1;
664 p = zombproc;
665 }
666 if (p == NULL) {
667 /* Extend 'reclen' to end of block */;
668 dent.d_reclen = DIRBLKSIZ - (count & (DIRBLKSIZ - 1));
669 } else
670 dent.d_reclen = sizeof(struct pfsdent);
671 count += dent.d_reclen;
672 error = uiomove((char *)&dent, dent.d_reclen, uio);
673 if (error)
674 break;
675 }
676 if (count == 0)
677 *eofflagp = 1;
678
679 uio->uio_resid += lost;
680 return error;
681}
682
683/*
684 * convert n to decimal representation in character array b
685 * return number of decimal digits produced.
686 */
687int
688itos(n, b)
689unsigned int n;
690char *b;
691{
692#define BASE 10
693 int m = (n<BASE)?0:itos(n/BASE, b);
694
695 *(b+m) = "0123456789abcdef"[n%BASE];
696 return m+1;
697}
698
699/*
700 * convert decimal ascii representation in b of length len to integer
701 */
702int
703atoi(b, len)
704char *b;
705unsigned int len;
706{
707 int n = 0;
708
709 while (len--) {
710 register char c = *b++;
711 if (c < '0' || c > '9')
712 return -1;
713 n = 10 * n + (c - '0');
714 }
715 return n;
716}