From 7153ad2b728f68109a0cc544d2918b5e77367d57 Mon Sep 17 00:00:00 2001 From: Mikolaj Golub Date: Sat, 20 Apr 2013 07:47:26 +0000 Subject: Make libprocstat(3) extract procstat notes from a process core file. PR: kern/173723 Suggested by: jhb Glanced by: kib MFC after: 1 month --- lib/libprocstat/Makefile | 5 +- lib/libprocstat/Symbol.map | 1 + lib/libprocstat/core.c | 262 +++++++++++++++++++++++++++++++++ lib/libprocstat/core.h | 45 ++++++ lib/libprocstat/libprocstat.3 | 23 ++- lib/libprocstat/libprocstat.c | 132 +++++++++++++++-- lib/libprocstat/libprocstat.h | 1 + lib/libprocstat/libprocstat_internal.h | 1 + 8 files changed, 453 insertions(+), 17 deletions(-) create mode 100644 lib/libprocstat/core.c create mode 100644 lib/libprocstat/core.h (limited to 'lib/libprocstat') diff --git a/lib/libprocstat/Makefile b/lib/libprocstat/Makefile index a29afc7a7d8d..1ba2398ace5b 100644 --- a/lib/libprocstat/Makefile +++ b/lib/libprocstat/Makefile @@ -6,6 +6,7 @@ LIB= procstat SRCS= cd9660.c \ common_kvm.c \ + core.c \ libprocstat.c \ msdosfs.c \ udf.c @@ -17,8 +18,8 @@ INCS= libprocstat.h CFLAGS+= -I. -I${.CURDIR} -D_KVM_VNODE SHLIB_MAJOR= 1 -DPADD= ${LIBKVM} ${LIBUTIL} -LDADD= -lkvm -lutil +DPADD= ${LIBELF} ${LIBKVM} ${LIBUTIL} +LDADD= -lelf -lkvm -lutil MAN= libprocstat.3 diff --git a/lib/libprocstat/Symbol.map b/lib/libprocstat/Symbol.map index 0509066369f0..a078090f1eb7 100644 --- a/lib/libprocstat/Symbol.map +++ b/lib/libprocstat/Symbol.map @@ -17,4 +17,5 @@ FBSD_1.2 { FBSD_1.3 { procstat_get_shm_info; + procstat_open_core; }; diff --git a/lib/libprocstat/core.c b/lib/libprocstat/core.c new file mode 100644 index 000000000000..1ada45927de3 --- /dev/null +++ b/lib/libprocstat/core.c @@ -0,0 +1,262 @@ +/*- + * Copyright (c) 2013 Mikolaj Golub + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "core.h" + +#define PROCSTAT_CORE_MAGIC 0x012DADB8 +struct procstat_core +{ + int pc_magic; + int pc_fd; + Elf *pc_elf; + GElf_Ehdr pc_ehdr; + GElf_Phdr pc_phdr; +}; + +static bool core_offset(struct procstat_core *core, off_t offset); +static bool core_read(struct procstat_core *core, void *buf, size_t len); + +struct procstat_core * +procstat_core_open(const char *filename) +{ + struct procstat_core *core; + Elf *e; + GElf_Ehdr ehdr; + GElf_Phdr phdr; + size_t nph; + int fd, i; + + if (elf_version(EV_CURRENT) == EV_NONE) { + warnx("ELF library too old"); + return (NULL); + } + fd = open(filename, O_RDONLY, 0); + if (fd == -1) { + warn("open(%s)", filename); + return (NULL); + } + e = elf_begin(fd, ELF_C_READ, NULL); + if (e == NULL) { + warnx("elf_begin: %s", elf_errmsg(-1)); + goto fail; + } + if (elf_kind(e) != ELF_K_ELF) { + warnx("%s is not an ELF object", filename); + goto fail; + } + if (gelf_getehdr(e, &ehdr) == NULL) { + warnx("gelf_getehdr: %s", elf_errmsg(-1)); + goto fail; + } + if (ehdr.e_type != ET_CORE) { + warnx("%s is not a CORE file", filename); + goto fail; + } + if (elf_getphnum(e, &nph) == 0) { + warnx("program headers not found"); + goto fail; + } + for (i = 0; i < ehdr.e_phnum; i++) { + if (gelf_getphdr(e, i, &phdr) != &phdr) { + warnx("gelf_getphdr: %s", elf_errmsg(-1)); + goto fail; + } + if (phdr.p_type == PT_NOTE) + break; + } + if (i == ehdr.e_phnum) { + warnx("NOTE program header not found"); + goto fail; + } + core = malloc(sizeof(struct procstat_core)); + if (core == NULL) { + warn("malloc(%zu)", sizeof(struct procstat_core)); + goto fail; + } + core->pc_magic = PROCSTAT_CORE_MAGIC; + core->pc_fd = fd; + core->pc_elf = e; + core->pc_ehdr = ehdr; + core->pc_phdr = phdr; + + return (core); +fail: + if (e != NULL) + elf_end(e); + close(fd); + + return (NULL); +} + +void +procstat_core_close(struct procstat_core *core) +{ + + assert(core->pc_magic == PROCSTAT_CORE_MAGIC); + + elf_end(core->pc_elf); + close(core->pc_fd); + free(core); +} + +void * +procstat_core_get(struct procstat_core *core, enum psc_type type, void *buf, + size_t *lenp) +{ + Elf_Note nhdr; + off_t offset, eoffset; + void *freebuf; + size_t len; + u_int32_t n_type; + int cstructsize, structsize; + char nbuf[8]; + + assert(core->pc_magic == PROCSTAT_CORE_MAGIC); + + switch(type) { + case PSC_TYPE_PROC: + n_type = NT_PROCSTAT_PROC; + structsize = sizeof(struct kinfo_proc); + break; + case PSC_TYPE_FILES: + n_type = NT_PROCSTAT_FILES; + structsize = sizeof(struct kinfo_file); + break; + case PSC_TYPE_VMMAP: + n_type = NT_PROCSTAT_VMMAP; + structsize = sizeof(struct kinfo_vmentry); + break; + default: + warnx("unknown core stat type: %d", type); + return (NULL); + } + + offset = core->pc_phdr.p_offset; + eoffset = offset + core->pc_phdr.p_filesz; + + while (offset < eoffset) { + if (!core_offset(core, offset)) + return (NULL); + if (!core_read(core, &nhdr, sizeof(nhdr))) + return (NULL); + + offset += sizeof(nhdr) + + roundup2(nhdr.n_namesz, sizeof(Elf32_Size)) + + roundup2(nhdr.n_descsz, sizeof(Elf32_Size)); + + if (nhdr.n_namesz == 0 && nhdr.n_descsz == 0) + break; + if (nhdr.n_type != n_type) + continue; + if (nhdr.n_namesz != 8) + continue; + if (!core_read(core, nbuf, sizeof(nbuf))) + return (NULL); + if (strcmp(nbuf, "FreeBSD") != 0) + continue; + if (nhdr.n_descsz < sizeof(cstructsize)) { + warnx("corrupted core file"); + return (NULL); + } + if (!core_read(core, &cstructsize, sizeof(cstructsize))) + return (NULL); + if (cstructsize != structsize) { + warnx("version mismatch"); + return (NULL); + } + len = nhdr.n_descsz - sizeof(cstructsize); + if (len == 0) + return (NULL); + if (buf != NULL) { + len = MIN(len, *lenp); + freebuf = NULL; + } else { + freebuf = buf = malloc(len); + if (buf == NULL) { + warn("malloc(%zu)", len); + return (NULL); + } + } + if (!core_read(core, buf, len)) { + free(freebuf); + return (NULL); + } + *lenp = len; + return (buf); + } + + return (NULL); +} + +static bool +core_offset(struct procstat_core *core, off_t offset) +{ + + assert(core->pc_magic == PROCSTAT_CORE_MAGIC); + + if (lseek(core->pc_fd, offset, SEEK_SET) == -1) { + warn("core: lseek(%jd)", (intmax_t)offset); + return (false); + } + return (true); +} + +static bool +core_read(struct procstat_core *core, void *buf, size_t len) +{ + ssize_t n; + + assert(core->pc_magic == PROCSTAT_CORE_MAGIC); + + n = read(core->pc_fd, buf, len); + if (n == -1) { + warn("core: read"); + return (false); + } + if (n < (ssize_t)len) { + warnx("core: short read"); + return (false); + } + return (true); +} diff --git a/lib/libprocstat/core.h b/lib/libprocstat/core.h new file mode 100644 index 000000000000..8e2dd13ff4d1 --- /dev/null +++ b/lib/libprocstat/core.h @@ -0,0 +1,45 @@ +/*- + * Copyright (c) 2013 Mikolaj Golub + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _CORE_H +#define _CORE_H + +enum psc_type { + PSC_TYPE_PROC, + PSC_TYPE_FILES, + PSC_TYPE_VMMAP, +}; + +struct procstat_core; + +void procstat_core_close(struct procstat_core *core); +void *procstat_core_get(struct procstat_core *core, enum psc_type type, + void * buf, size_t *lenp); +struct procstat_core *procstat_core_open(const char *filename); + +#endif /* !_CORE_H_ */ diff --git a/lib/libprocstat/libprocstat.3 b/lib/libprocstat/libprocstat.3 index dd163c214cd0..a64376c70d9a 100644 --- a/lib/libprocstat/libprocstat.3 +++ b/lib/libprocstat/libprocstat.3 @@ -28,6 +28,7 @@ .Dt LIBPROCSTAT 3 .Os .Sh NAME +.Nm procstat_open_core , .Nm procstat_open_kvm , .Nm procstat_open_sysctl , .Nm procstat_close , @@ -105,6 +106,8 @@ .Fa "unsigned int *count" .Fc .Ft "struct procstat *" +.Fn procstat_open_core "const char *filename" +.Ft "struct procstat *" .Fn procstat_open_kvm "const char *nlistf" "const char *memf" .Ft "struct procstat *" .Fn procstat_open_sysctl void @@ -116,7 +119,11 @@ retrieval from the running kernel via the .Xr sysctl 3 library backend, and for post-mortem analysis via the .Xr kvm 3 -library backend. +library backend, or from the process +.Xr core 5 +file, searching for statistics in special +.Xr elf 3 +note sections. .Pp The .Fn procstat_open_kvm @@ -129,6 +136,16 @@ or library routines, respectively, to access kernel state information used to retrieve processes and files states. The +.Fn procstat_open_core +uses +.Xr elf 3 +routines to access statistics stored as a set of notes in a process +.Xr core 5 +file, written by the kernel at the moment of the process abnormal termination. +The +.Fa filename +argument is the process core file name. +The .Fa nlistf argument is the executable image of the kernel being examined. If this argument is @@ -145,7 +162,7 @@ is assumed. See .Xr kvm_open 3 for more details. -Both functions dynamically allocate and return a +The functions dynamically allocate and return a .Vt procstat structure pointer used in the rest of the .Nm libprocstat @@ -250,10 +267,12 @@ argument indicates an actual error message in case of failure. .Xr pipe 2 , .Xr shm_open 2 , .Xr socket 2 , +.Xr elf 3 , .Xr kvm 3 , .Xr queue 3 , .Xr sysctl 3 , .Xr pts 4 , +.Xr core 5 , .Xr vnode 9 .Sh HISTORY The diff --git a/lib/libprocstat/libprocstat.c b/lib/libprocstat/libprocstat.c index f23ec96dfa2f..574d654641df 100644 --- a/lib/libprocstat/libprocstat.c +++ b/lib/libprocstat/libprocstat.c @@ -96,11 +96,13 @@ __FBSDID("$FreeBSD$"); #include #include "libprocstat_internal.h" #include "common_kvm.h" +#include "core.h" int statfs(const char *, struct statfs *); /* XXX */ #define PROCSTAT_KVM 1 #define PROCSTAT_SYSCTL 2 +#define PROCSTAT_CORE 3 static char *getmnton(kvm_t *kd, struct mount *m); static struct filestat_list *procstat_getfiles_kvm( @@ -137,6 +139,8 @@ procstat_close(struct procstat *procstat) assert(procstat); if (procstat->type == PROCSTAT_KVM) kvm_close(procstat->kd); + else if (procstat->type == PROCSTAT_CORE) + procstat_core_close(procstat->core); free(procstat); } @@ -177,6 +181,27 @@ procstat_open_kvm(const char *nlistf, const char *memf) return (procstat); } +struct procstat * +procstat_open_core(const char *filename) +{ + struct procstat *procstat; + struct procstat_core *core; + + procstat = calloc(1, sizeof(*procstat)); + if (procstat == NULL) { + warn("malloc()"); + return (NULL); + } + core = procstat_core_open(filename); + if (core == NULL) { + free(procstat); + return (NULL); + } + procstat->type = PROCSTAT_CORE; + procstat->core = core; + return (procstat); +} + struct kinfo_proc * procstat_getprocs(struct procstat *procstat, int what, int arg, unsigned int *count) @@ -230,6 +255,15 @@ procstat_getprocs(struct procstat *procstat, int what, int arg, goto fail; } /* Perform simple consistency checks. */ + if ((len % sizeof(*p)) != 0 || p->ki_structsize != sizeof(*p)) { + warnx("kinfo_proc structure size mismatch (len = %zu)", len); + goto fail; + } + *count = len / sizeof(*p); + return (p); + } else if (procstat->type == PROCSTAT_CORE) { + p = procstat_core_get(procstat->core, PSC_TYPE_PROC, NULL, + &len); if ((len % sizeof(*p)) != 0 || p->ki_structsize != sizeof(*p)) { warnx("kinfo_proc structure size mismatch"); goto fail; @@ -258,13 +292,17 @@ procstat_freeprocs(struct procstat *procstat __unused, struct kinfo_proc *p) struct filestat_list * procstat_getfiles(struct procstat *procstat, struct kinfo_proc *kp, int mmapped) { - - if (procstat->type == PROCSTAT_SYSCTL) - return (procstat_getfiles_sysctl(procstat, kp, mmapped)); - else if (procstat->type == PROCSTAT_KVM) + + switch(procstat->type) { + case PROCSTAT_KVM: return (procstat_getfiles_kvm(procstat, kp, mmapped)); - else + case PROCSTAT_SYSCTL: + case PROCSTAT_CORE: + return (procstat_getfiles_sysctl(procstat, kp, mmapped)); + default: + warnx("unknown access method: %d", procstat->type); return (NULL); + } } void @@ -646,8 +684,62 @@ kinfo_uflags2fst(int fd) return (0); } +static struct kinfo_file * +kinfo_getfile_core(struct procstat_core *core, int *cntp) +{ + int cnt; + size_t len; + char *buf, *bp, *eb; + struct kinfo_file *kif, *kp, *kf; + + buf = procstat_core_get(core, PSC_TYPE_FILES, NULL, &len); + if (buf == NULL) + return (NULL); + /* + * XXXMG: The code below is just copy&past from libutil. + * The code duplication can be avoided if libutil + * is extended to provide something like: + * struct kinfo_file *kinfo_getfile_from_buf(const char *buf, + * size_t len, int *cntp); + */ + + /* Pass 1: count items */ + cnt = 0; + bp = buf; + eb = buf + len; + while (bp < eb) { + kf = (struct kinfo_file *)(uintptr_t)bp; + bp += kf->kf_structsize; + cnt++; + } + + kif = calloc(cnt, sizeof(*kif)); + if (kif == NULL) { + free(buf); + return (NULL); + } + bp = buf; + eb = buf + len; + kp = kif; + /* Pass 2: unpack */ + while (bp < eb) { + kf = (struct kinfo_file *)(uintptr_t)bp; + /* Copy/expand into pre-zeroed buffer */ + memcpy(kp, kf, kf->kf_structsize); + /* Advance to next packed record */ + bp += kf->kf_structsize; + /* Set field size to fixed length, advance */ + kp->kf_structsize = sizeof(*kp); + kp++; + } + free(buf); + *cntp = cnt; + return (kif); /* Caller must free() return value */ +} + static struct filestat_list * -procstat_getfiles_sysctl(struct procstat *procstat, struct kinfo_proc *kp, int mmapped) +procstat_getfiles_sysctl(struct procstat *procstat, struct kinfo_proc *kp, + int mmapped) { struct kinfo_file *kif, *files; struct kinfo_vmentry *kve, *vmentries; @@ -663,8 +755,16 @@ procstat_getfiles_sysctl(struct procstat *procstat, struct kinfo_proc *kp, int m assert(kp); if (kp->ki_fd == NULL) return (NULL); - - files = kinfo_getfile(kp->ki_pid, &cnt); + switch(procstat->type) { + case PROCSTAT_SYSCTL: + files = kinfo_getfile(kp->ki_pid, &cnt); + break; + case PROCSTAT_CORE: + files = kinfo_getfile_core(procstat->core, &cnt); + break; + default: + assert(!"invalid type"); + } if (files == NULL && errno != EPERM) { warn("kinfo_getfile()"); return (NULL); @@ -742,7 +842,8 @@ procstat_get_pipe_info(struct procstat *procstat, struct filestat *fst, if (procstat->type == PROCSTAT_KVM) { return (procstat_get_pipe_info_kvm(procstat->kd, fst, ps, errbuf)); - } else if (procstat->type == PROCSTAT_SYSCTL) { + } else if (procstat->type == PROCSTAT_SYSCTL || + procstat->type == PROCSTAT_CORE) { return (procstat_get_pipe_info_sysctl(fst, ps, errbuf)); } else { warnx("unknown access method: %d", procstat->type); @@ -806,7 +907,8 @@ procstat_get_pts_info(struct procstat *procstat, struct filestat *fst, if (procstat->type == PROCSTAT_KVM) { return (procstat_get_pts_info_kvm(procstat->kd, fst, pts, errbuf)); - } else if (procstat->type == PROCSTAT_SYSCTL) { + } else if (procstat->type == PROCSTAT_SYSCTL || + procstat->type == PROCSTAT_CORE) { return (procstat_get_pts_info_sysctl(fst, pts, errbuf)); } else { warnx("unknown access method: %d", procstat->type); @@ -868,7 +970,8 @@ procstat_get_shm_info(struct procstat *procstat, struct filestat *fst, if (procstat->type == PROCSTAT_KVM) { return (procstat_get_shm_info_kvm(procstat->kd, fst, shm, errbuf)); - } else if (procstat->type == PROCSTAT_SYSCTL) { + } else if (procstat->type == PROCSTAT_SYSCTL || + procstat->type == PROCSTAT_CORE) { return (procstat_get_shm_info_sysctl(fst, shm, errbuf)); } else { warnx("unknown access method: %d", procstat->type); @@ -948,7 +1051,8 @@ procstat_get_vnode_info(struct procstat *procstat, struct filestat *fst, if (procstat->type == PROCSTAT_KVM) { return (procstat_get_vnode_info_kvm(procstat->kd, fst, vn, errbuf)); - } else if (procstat->type == PROCSTAT_SYSCTL) { + } else if (procstat->type == PROCSTAT_SYSCTL || + procstat->type == PROCSTAT_CORE) { return (procstat_get_vnode_info_sysctl(fst, vn, errbuf)); } else { warnx("unknown access method: %d", procstat->type); @@ -1150,7 +1254,8 @@ procstat_get_socket_info(struct procstat *procstat, struct filestat *fst, if (procstat->type == PROCSTAT_KVM) { return (procstat_get_socket_info_kvm(procstat->kd, fst, sock, errbuf)); - } else if (procstat->type == PROCSTAT_SYSCTL) { + } else if (procstat->type == PROCSTAT_SYSCTL || + procstat->type == PROCSTAT_CORE) { return (procstat_get_socket_info_sysctl(fst, sock, errbuf)); } else { warnx("unknown access method: %d", procstat->type); @@ -1401,3 +1506,4 @@ getmnton(kvm_t *kd, struct mount *m) mhead = mt; return (mt->mntonname); } + diff --git a/lib/libprocstat/libprocstat.h b/lib/libprocstat/libprocstat.h index 1c55aa756200..4ad9ceefc4a3 100644 --- a/lib/libprocstat/libprocstat.h +++ b/lib/libprocstat/libprocstat.h @@ -162,6 +162,7 @@ int procstat_get_socket_info(struct procstat *procstat, struct filestat *fst, struct sockstat *sock, char *errbuf); int procstat_get_vnode_info(struct procstat *procstat, struct filestat *fst, struct vnstat *vn, char *errbuf); +struct procstat *procstat_open_core(const char *filename); struct procstat *procstat_open_sysctl(void); struct procstat *procstat_open_kvm(const char *nlistf, const char *memf); __END_DECLS diff --git a/lib/libprocstat/libprocstat_internal.h b/lib/libprocstat/libprocstat_internal.h index 1c1d84284701..ff1e742f4611 100644 --- a/lib/libprocstat/libprocstat_internal.h +++ b/lib/libprocstat/libprocstat_internal.h @@ -34,6 +34,7 @@ struct procstat { kvm_t *kd; void *vmentries; void *files; + struct procstat_core *core; }; #endif /* !_LIBPROCSTAT_INTERNAL_H_ */ -- cgit v1.3 From 39680c7bfb04a16293438e6be156782213a7c1f5 Mon Sep 17 00:00:00 2001 From: Mikolaj Golub Date: Sat, 20 Apr 2013 07:49:35 +0000 Subject: Add procstat_getvmmap function to get VM layout of a process. MFC after: 1 month --- lib/libprocstat/Symbol.map | 2 ++ lib/libprocstat/libprocstat.3 | 29 +++++++++++++++ lib/libprocstat/libprocstat.c | 83 ++++++++++++++++++++++++++++++++++++++++++- lib/libprocstat/libprocstat.h | 5 +++ 4 files changed, 118 insertions(+), 1 deletion(-) (limited to 'lib/libprocstat') diff --git a/lib/libprocstat/Symbol.map b/lib/libprocstat/Symbol.map index a078090f1eb7..aa7465989c90 100644 --- a/lib/libprocstat/Symbol.map +++ b/lib/libprocstat/Symbol.map @@ -16,6 +16,8 @@ FBSD_1.2 { }; FBSD_1.3 { + procstat_freevmmap; procstat_get_shm_info; + procstat_getvmmap; procstat_open_core; }; diff --git a/lib/libprocstat/libprocstat.3 b/lib/libprocstat/libprocstat.3 index a64376c70d9a..18dc1e9f1b23 100644 --- a/lib/libprocstat/libprocstat.3 +++ b/lib/libprocstat/libprocstat.3 @@ -34,8 +34,10 @@ .Nm procstat_close , .Nm procstat_getfiles , .Nm procstat_getprocs , +.Nm procstat_getvmmap , .Nm procstat_freefiles , .Nm procstat_freeprocs , +.Nm procstat_freevmmap , .Nm procstat_get_pipe_info , .Nm procstat_get_pts_info , .Nm procstat_get_shm_info , @@ -57,6 +59,11 @@ .Fc .Ft void .Fn procstat_freeprocs "struct procstat *procstat" "struct kinfo_proc *p" +.Ft void +.Fo procstat_freevmmap +.Fa "struct procstat *procstat" +.Fa "struct kinfo_vmentry *vmmap" +.Fc .Ft int .Fo procstat_get_pipe_info .Fa "struct procstat *procstat" @@ -105,6 +112,12 @@ .Fa "int arg" .Fa "unsigned int *count" .Fc +.Ft "struct kinfo_vmentry *" +.Fo procstat_getvmmap +.Fa "struct procstat *procstat" +.Fa "struct kinfo_proc *kp" +.Fa "unsigned int *count" +.Fc .Ft "struct procstat *" .Fn procstat_open_core "const char *filename" .Ft "struct procstat *" @@ -214,6 +227,22 @@ The caller is responsible to free the allocated memory with a subsequent function call. .Pp The +.Fn procstat_getvmmap +function gets a pointer to the +.Vt procstat +structure initialized with one of the +.Fn procstat_open_* +functions, a pointer to +.Vt kinfo_proc +structure, and returns VM layout of the process as a dynamically allocated +array of +.Vt kinfo_vmentry +structures. +The caller is responsible to free the allocated memory with a subsequent +.Fn procstat_freevmmap +function call. +.Pp +The .Fn procstat_get_pipe_info , .Fn procstat_get_pts_info , .Fn procstat_get_shm_info , diff --git a/lib/libprocstat/libprocstat.c b/lib/libprocstat/libprocstat.c index 574d654641df..283f80281831 100644 --- a/lib/libprocstat/libprocstat.c +++ b/lib/libprocstat/libprocstat.c @@ -105,6 +105,8 @@ int statfs(const char *, struct statfs *); /* XXX */ #define PROCSTAT_CORE 3 static char *getmnton(kvm_t *kd, struct mount *m); +static struct kinfo_vmentry * kinfo_getvmmap_core(struct procstat_core *core, + int *cntp); static struct filestat_list *procstat_getfiles_kvm( struct procstat *procstat, struct kinfo_proc *kp, int mmapped); static struct filestat_list *procstat_getfiles_sysctl( @@ -802,7 +804,7 @@ procstat_getfiles_sysctl(struct procstat *procstat, struct kinfo_proc *kp, STAILQ_INSERT_TAIL(head, entry, next); } if (mmapped != 0) { - vmentries = kinfo_getvmmap(kp->ki_pid, &cnt); + vmentries = procstat_getvmmap(procstat, kp, &cnt); procstat->vmentries = vmentries; if (vmentries == NULL || cnt == 0) goto fail; @@ -1507,3 +1509,82 @@ getmnton(kvm_t *kd, struct mount *m) return (mt->mntonname); } +static struct kinfo_vmentry * +kinfo_getvmmap_core(struct procstat_core *core, int *cntp) +{ + int cnt; + size_t len; + char *buf, *bp, *eb; + struct kinfo_vmentry *kiv, *kp, *kv; + + buf = procstat_core_get(core, PSC_TYPE_VMMAP, NULL, &len); + if (buf == NULL) + return (NULL); + + /* + * XXXMG: The code below is just copy&past from libutil. + * The code duplication can be avoided if libutil + * is extended to provide something like: + * struct kinfo_vmentry *kinfo_getvmmap_from_buf(const char *buf, + * size_t len, int *cntp); + */ + + /* Pass 1: count items */ + cnt = 0; + bp = buf; + eb = buf + len; + while (bp < eb) { + kv = (struct kinfo_vmentry *)(uintptr_t)bp; + bp += kv->kve_structsize; + cnt++; + } + + kiv = calloc(cnt, sizeof(*kiv)); + if (kiv == NULL) { + free(buf); + return (NULL); + } + bp = buf; + eb = buf + len; + kp = kiv; + /* Pass 2: unpack */ + while (bp < eb) { + kv = (struct kinfo_vmentry *)(uintptr_t)bp; + /* Copy/expand into pre-zeroed buffer */ + memcpy(kp, kv, kv->kve_structsize); + /* Advance to next packed record */ + bp += kv->kve_structsize; + /* Set field size to fixed length, advance */ + kp->kve_structsize = sizeof(*kp); + kp++; + } + free(buf); + *cntp = cnt; + return (kiv); /* Caller must free() return value */ +} + +struct kinfo_vmentry * +procstat_getvmmap(struct procstat *procstat, struct kinfo_proc *kp, + unsigned int *cntp) +{ + switch(procstat->type) { + case PROCSTAT_KVM: + warnx("kvm method is not supported"); + return (NULL); + case PROCSTAT_SYSCTL: + return (kinfo_getvmmap(kp->ki_pid, cntp)); + case PROCSTAT_CORE: + return (kinfo_getvmmap_core(procstat->core, cntp)); + default: + warnx("unknown access method: %d", procstat->type); + return (NULL); + } +} + +void +procstat_freevmmap(struct procstat *procstat __unused, + struct kinfo_vmentry *vmmap) +{ + + free(vmmap); +} diff --git a/lib/libprocstat/libprocstat.h b/lib/libprocstat/libprocstat.h index 4ad9ceefc4a3..71d85a11bb5f 100644 --- a/lib/libprocstat/libprocstat.h +++ b/lib/libprocstat/libprocstat.h @@ -89,6 +89,7 @@ #define PS_FST_FFLAG_EXEC 0x2000 #define PS_FST_FFLAG_HASLOCK 0x4000 +struct kinfo_vmentry; struct procstat; struct filestat { int fs_type; /* Descriptor type. */ @@ -148,6 +149,8 @@ void procstat_close(struct procstat *procstat); void procstat_freeprocs(struct procstat *procstat, struct kinfo_proc *p); void procstat_freefiles(struct procstat *procstat, struct filestat_list *head); +void procstat_freevmmap(struct procstat *procstat, + struct kinfo_vmentry *vmmap); struct filestat_list *procstat_getfiles(struct procstat *procstat, struct kinfo_proc *kp, int mmapped); struct kinfo_proc *procstat_getprocs(struct procstat *procstat, @@ -162,6 +165,8 @@ int procstat_get_socket_info(struct procstat *procstat, struct filestat *fst, struct sockstat *sock, char *errbuf); int procstat_get_vnode_info(struct procstat *procstat, struct filestat *fst, struct vnstat *vn, char *errbuf); +struct kinfo_vmentry *procstat_getvmmap(struct procstat *procstat, + struct kinfo_proc *kp, unsigned int *count); struct procstat *procstat_open_core(const char *filename); struct procstat *procstat_open_sysctl(void); struct procstat *procstat_open_kvm(const char *nlistf, const char *memf); -- cgit v1.3 From 7f1d14e6e67f6c42b23d598a811cb3593302f6c4 Mon Sep 17 00:00:00 2001 From: Mikolaj Golub Date: Sat, 20 Apr 2013 07:54:07 +0000 Subject: Add procstat_getgroups function to retrieve process groups. MFC after: 1 month --- lib/libprocstat/Symbol.map | 2 ++ lib/libprocstat/core.c | 4 +++ lib/libprocstat/core.h | 1 + lib/libprocstat/libprocstat.3 | 27 +++++++++++++++++ lib/libprocstat/libprocstat.c | 67 +++++++++++++++++++++++++++++++++++++++++++ lib/libprocstat/libprocstat.h | 3 ++ 6 files changed, 104 insertions(+) (limited to 'lib/libprocstat') diff --git a/lib/libprocstat/Symbol.map b/lib/libprocstat/Symbol.map index aa7465989c90..5ac5ee1f08ed 100644 --- a/lib/libprocstat/Symbol.map +++ b/lib/libprocstat/Symbol.map @@ -16,8 +16,10 @@ FBSD_1.2 { }; FBSD_1.3 { + procstat_freegroups; procstat_freevmmap; procstat_get_shm_info; + procstat_getgroups; procstat_getvmmap; procstat_open_core; }; diff --git a/lib/libprocstat/core.c b/lib/libprocstat/core.c index 1ada45927de3..afaa76c000fb 100644 --- a/lib/libprocstat/core.c +++ b/lib/libprocstat/core.c @@ -167,6 +167,10 @@ procstat_core_get(struct procstat_core *core, enum psc_type type, void *buf, n_type = NT_PROCSTAT_VMMAP; structsize = sizeof(struct kinfo_vmentry); break; + case PSC_TYPE_GROUPS: + n_type = NT_PROCSTAT_GROUPS; + structsize = sizeof(gid_t); + break; default: warnx("unknown core stat type: %d", type); return (NULL); diff --git a/lib/libprocstat/core.h b/lib/libprocstat/core.h index 8e2dd13ff4d1..54efa29464bc 100644 --- a/lib/libprocstat/core.h +++ b/lib/libprocstat/core.h @@ -33,6 +33,7 @@ enum psc_type { PSC_TYPE_PROC, PSC_TYPE_FILES, PSC_TYPE_VMMAP, + PSC_TYPE_GROUPS, }; struct procstat_core; diff --git a/lib/libprocstat/libprocstat.3 b/lib/libprocstat/libprocstat.3 index 18dc1e9f1b23..b38ce1c44baf 100644 --- a/lib/libprocstat/libprocstat.3 +++ b/lib/libprocstat/libprocstat.3 @@ -33,9 +33,11 @@ .Nm procstat_open_sysctl , .Nm procstat_close , .Nm procstat_getfiles , +.Nm procstat_getgroups , .Nm procstat_getprocs , .Nm procstat_getvmmap , .Nm procstat_freefiles , +.Nm procstat_freegroups , .Nm procstat_freeprocs , .Nm procstat_freevmmap , .Nm procstat_get_pipe_info , @@ -52,12 +54,18 @@ .In libprocstat.h .Ft void .Fn procstat_close "struct procstat *procstat" +.Fc .Ft void .Fo procstat_freefiles .Fa "struct procstat *procstat" .Fa "struct filestat_list *head" .Fc .Ft void +.Fo procstat_freegroups +.Fa "struct procstat *procstat" +.Fa "gid_t *groups" +.Fc +.Ft void .Fn procstat_freeprocs "struct procstat *procstat" "struct kinfo_proc *p" .Ft void .Fo procstat_freevmmap @@ -105,6 +113,12 @@ .Fa "struct kinfo_proc *kp" .Fa "int mmapped" .Fc +.Ft "gid_t *" +.Fo procstat_getgroups +.Fa "struct procstat *procstat" +.Fa "struct kinfo_proc *kp" +.Fa "unsigned int *count" +.Fc .Ft "struct kinfo_proc *" .Fo procstat_getprocs .Fa "struct procstat *procstat" @@ -227,6 +241,19 @@ The caller is responsible to free the allocated memory with a subsequent function call. .Pp The +.Fn procstat_getgroups +function gets a pointer to the +.Vt procstat +structure, a pointer to +.Vt kinfo_proc +structure, and returns the process groups as a dynamically allocated array of +.Vt gid_t +elements. +The caller is responsible to free the allocated memory with a subsequent +.Fn procstat_freegroups +function call. +.Pp +The .Fn procstat_getvmmap function gets a pointer to the .Vt procstat diff --git a/lib/libprocstat/libprocstat.c b/lib/libprocstat/libprocstat.c index 283f80281831..b300b1f01086 100644 --- a/lib/libprocstat/libprocstat.c +++ b/lib/libprocstat/libprocstat.c @@ -132,6 +132,9 @@ static int procstat_get_vnode_info_kvm(kvm_t *kd, struct filestat *fst, struct vnstat *vn, char *errbuf); static int procstat_get_vnode_info_sysctl(struct filestat *fst, struct vnstat *vn, char *errbuf); +static gid_t *procstat_getgroups_core(struct procstat_core *core, + unsigned int *count); +static gid_t *procstat_getgroups_sysctl(pid_t pid, unsigned int *count); static int vntype2psfsttype(int type); void @@ -1588,3 +1591,67 @@ procstat_freevmmap(struct procstat *procstat __unused, free(vmmap); } + +static gid_t * +procstat_getgroups_sysctl(pid_t pid, unsigned int *cntp) +{ + int mib[4]; + size_t len; + gid_t *groups; + + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_GROUPS; + mib[3] = pid; + len = (sysconf(_SC_NGROUPS_MAX) + 1) * sizeof(gid_t); + groups = malloc(len); + if (groups == NULL) { + warn("malloc(%zu)", len); + return (NULL); + } + if (sysctl(mib, 4, groups, &len, NULL, 0) == -1) { + warn("sysctl: kern.proc.groups: %d", pid); + free(groups); + return (NULL); + } + *cntp = len / sizeof(gid_t); + return (groups); +} + +static gid_t * +procstat_getgroups_core(struct procstat_core *core, unsigned int *cntp) +{ + size_t len; + gid_t *groups; + + groups = procstat_core_get(core, PSC_TYPE_GROUPS, NULL, &len); + if (groups == NULL) + return (NULL); + *cntp = len / sizeof(gid_t); + return (groups); +} + +gid_t * +procstat_getgroups(struct procstat *procstat, struct kinfo_proc *kp, + unsigned int *cntp) +{ + switch(procstat->type) { + case PROCSTAT_KVM: + warnx("kvm method is not supported"); + return (NULL); + case PROCSTAT_SYSCTL: + return (procstat_getgroups_sysctl(kp->ki_pid, cntp)); + case PROCSTAT_CORE: + return (procstat_getgroups_core(procstat->core, cntp)); + default: + warnx("unknown access method: %d", procstat->type); + return (NULL); + } +} + +void +procstat_freegroups(struct procstat *procstat __unused, gid_t *groups) +{ + + free(groups); +} diff --git a/lib/libprocstat/libprocstat.h b/lib/libprocstat/libprocstat.h index 71d85a11bb5f..0c4e77a6c8e9 100644 --- a/lib/libprocstat/libprocstat.h +++ b/lib/libprocstat/libprocstat.h @@ -146,6 +146,7 @@ STAILQ_HEAD(filestat_list, filestat); __BEGIN_DECLS void procstat_close(struct procstat *procstat); +void procstat_freegroups(struct procstat *procstat, gid_t *groups); void procstat_freeprocs(struct procstat *procstat, struct kinfo_proc *p); void procstat_freefiles(struct procstat *procstat, struct filestat_list *head); @@ -165,6 +166,8 @@ int procstat_get_socket_info(struct procstat *procstat, struct filestat *fst, struct sockstat *sock, char *errbuf); int procstat_get_vnode_info(struct procstat *procstat, struct filestat *fst, struct vnstat *vn, char *errbuf); +gid_t *procstat_getgroups(struct procstat *procstat, struct kinfo_proc *kp, + unsigned int *count); struct kinfo_vmentry *procstat_getvmmap(struct procstat *procstat, struct kinfo_proc *kp, unsigned int *count); struct procstat *procstat_open_core(const char *filename); -- cgit v1.3 From 5b9bcba971ab2c6bc9f1240e43ac8459e1de9075 Mon Sep 17 00:00:00 2001 From: Mikolaj Golub Date: Sat, 20 Apr 2013 07:57:08 +0000 Subject: Add procstat_getumask function to retrieve a process umask. MFC after: 1 month --- lib/libprocstat/Symbol.map | 1 + lib/libprocstat/core.c | 4 +++ lib/libprocstat/core.h | 1 + lib/libprocstat/libprocstat.3 | 15 ++++++++++++ lib/libprocstat/libprocstat.c | 57 +++++++++++++++++++++++++++++++++++++++++++ lib/libprocstat/libprocstat.h | 2 ++ 6 files changed, 80 insertions(+) (limited to 'lib/libprocstat') diff --git a/lib/libprocstat/Symbol.map b/lib/libprocstat/Symbol.map index 5ac5ee1f08ed..1970a7a2d944 100644 --- a/lib/libprocstat/Symbol.map +++ b/lib/libprocstat/Symbol.map @@ -20,6 +20,7 @@ FBSD_1.3 { procstat_freevmmap; procstat_get_shm_info; procstat_getgroups; + procstat_getumask; procstat_getvmmap; procstat_open_core; }; diff --git a/lib/libprocstat/core.c b/lib/libprocstat/core.c index afaa76c000fb..5732f406643f 100644 --- a/lib/libprocstat/core.c +++ b/lib/libprocstat/core.c @@ -171,6 +171,10 @@ procstat_core_get(struct procstat_core *core, enum psc_type type, void *buf, n_type = NT_PROCSTAT_GROUPS; structsize = sizeof(gid_t); break; + case PSC_TYPE_UMASK: + n_type = NT_PROCSTAT_UMASK; + structsize = sizeof(u_short); + break; default: warnx("unknown core stat type: %d", type); return (NULL); diff --git a/lib/libprocstat/core.h b/lib/libprocstat/core.h index 54efa29464bc..6e7ed027b0c4 100644 --- a/lib/libprocstat/core.h +++ b/lib/libprocstat/core.h @@ -34,6 +34,7 @@ enum psc_type { PSC_TYPE_FILES, PSC_TYPE_VMMAP, PSC_TYPE_GROUPS, + PSC_TYPE_UMASK, }; struct procstat_core; diff --git a/lib/libprocstat/libprocstat.3 b/lib/libprocstat/libprocstat.3 index b38ce1c44baf..06a66a06bca0 100644 --- a/lib/libprocstat/libprocstat.3 +++ b/lib/libprocstat/libprocstat.3 @@ -35,6 +35,7 @@ .Nm procstat_getfiles , .Nm procstat_getgroups , .Nm procstat_getprocs , +.Nm procstat_getumask , .Nm procstat_getvmmap , .Nm procstat_freefiles , .Nm procstat_freegroups , @@ -126,6 +127,12 @@ .Fa "int arg" .Fa "unsigned int *count" .Fc +.Ft "int" +.Fo procstat_getumask +.Fa "struct procstat *procstat" +.Fa "struct kinfo_proc *kp" +.Fa "unsigned short *maskp" +.Fc .Ft "struct kinfo_vmentry *" .Fo procstat_getvmmap .Fa "struct procstat *procstat" @@ -254,6 +261,14 @@ The caller is responsible to free the allocated memory with a subsequent function call. .Pp The +.Fn procstat_getumask +function gets a pointer to the +.Vt procstat +structure, a pointer to +.Vt kinfo_proc +structure, and returns the process umask in the 3rd reference parameter. +.Pp +The .Fn procstat_getvmmap function gets a pointer to the .Vt procstat diff --git a/lib/libprocstat/libprocstat.c b/lib/libprocstat/libprocstat.c index b300b1f01086..1ee0f973bebc 100644 --- a/lib/libprocstat/libprocstat.c +++ b/lib/libprocstat/libprocstat.c @@ -135,6 +135,9 @@ static int procstat_get_vnode_info_sysctl(struct filestat *fst, static gid_t *procstat_getgroups_core(struct procstat_core *core, unsigned int *count); static gid_t *procstat_getgroups_sysctl(pid_t pid, unsigned int *count); +static int procstat_getumask_core(struct procstat_core *core, + unsigned short *maskp); +static int procstat_getumask_sysctl(pid_t pid, unsigned short *maskp); static int vntype2psfsttype(int type); void @@ -1655,3 +1658,57 @@ procstat_freegroups(struct procstat *procstat __unused, gid_t *groups) free(groups); } + +static int +procstat_getumask_sysctl(pid_t pid, unsigned short *maskp) +{ + int error; + int mib[4]; + size_t len; + + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_UMASK; + mib[3] = pid; + len = sizeof(*maskp); + error = sysctl(mib, 4, maskp, &len, NULL, 0); + if (error != 0 && errno != ESRCH) + warn("sysctl: kern.proc.umask: %d", pid); + return (error); +} + +static int +procstat_getumask_core(struct procstat_core *core, unsigned short *maskp) +{ + size_t len; + unsigned short *buf; + + buf = procstat_core_get(core, PSC_TYPE_UMASK, NULL, &len); + if (buf == NULL) + return (-1); + if (len < sizeof(*maskp)) { + free(buf); + return (-1); + } + *maskp = *buf; + free(buf); + return (0); +} + +int +procstat_getumask(struct procstat *procstat, struct kinfo_proc *kp, + unsigned short *maskp) +{ + switch(procstat->type) { + case PROCSTAT_KVM: + warnx("kvm method is not supported"); + return (-1); + case PROCSTAT_SYSCTL: + return (procstat_getumask_sysctl(kp->ki_pid, maskp)); + case PROCSTAT_CORE: + return (procstat_getumask_core(procstat->core, maskp)); + default: + warnx("unknown access method: %d", procstat->type); + return (-1); + } +} diff --git a/lib/libprocstat/libprocstat.h b/lib/libprocstat/libprocstat.h index 0c4e77a6c8e9..8d14d0fa8936 100644 --- a/lib/libprocstat/libprocstat.h +++ b/lib/libprocstat/libprocstat.h @@ -168,6 +168,8 @@ int procstat_get_vnode_info(struct procstat *procstat, struct filestat *fst, struct vnstat *vn, char *errbuf); gid_t *procstat_getgroups(struct procstat *procstat, struct kinfo_proc *kp, unsigned int *count); +int procstat_getumask(struct procstat *procstat, struct kinfo_proc *kp, + unsigned short* umask); struct kinfo_vmentry *procstat_getvmmap(struct procstat *procstat, struct kinfo_proc *kp, unsigned int *count); struct procstat *procstat_open_core(const char *filename); -- cgit v1.3 From 7cc0ebfd10f73b2fdb7ef33a013ba38c4293d7ae Mon Sep 17 00:00:00 2001 From: Mikolaj Golub Date: Sat, 20 Apr 2013 07:59:44 +0000 Subject: Add procstat_getrlimit function to retrieve a process resource limits info. MFC after: 1 month --- lib/libprocstat/Symbol.map | 1 + lib/libprocstat/core.c | 4 +++ lib/libprocstat/core.h | 1 + lib/libprocstat/libprocstat.3 | 17 +++++++++++ lib/libprocstat/libprocstat.c | 68 +++++++++++++++++++++++++++++++++++++++++++ lib/libprocstat/libprocstat.h | 3 ++ 6 files changed, 94 insertions(+) (limited to 'lib/libprocstat') diff --git a/lib/libprocstat/Symbol.map b/lib/libprocstat/Symbol.map index 1970a7a2d944..461d32058ba1 100644 --- a/lib/libprocstat/Symbol.map +++ b/lib/libprocstat/Symbol.map @@ -20,6 +20,7 @@ FBSD_1.3 { procstat_freevmmap; procstat_get_shm_info; procstat_getgroups; + procstat_getrlimit; procstat_getumask; procstat_getvmmap; procstat_open_core; diff --git a/lib/libprocstat/core.c b/lib/libprocstat/core.c index 5732f406643f..2ff3975f69b7 100644 --- a/lib/libprocstat/core.c +++ b/lib/libprocstat/core.c @@ -175,6 +175,10 @@ procstat_core_get(struct procstat_core *core, enum psc_type type, void *buf, n_type = NT_PROCSTAT_UMASK; structsize = sizeof(u_short); break; + case PSC_TYPE_RLIMIT: + n_type = NT_PROCSTAT_RLIMIT; + structsize = sizeof(struct rlimit) * RLIM_NLIMITS; + break; default: warnx("unknown core stat type: %d", type); return (NULL); diff --git a/lib/libprocstat/core.h b/lib/libprocstat/core.h index 6e7ed027b0c4..967c1930c084 100644 --- a/lib/libprocstat/core.h +++ b/lib/libprocstat/core.h @@ -35,6 +35,7 @@ enum psc_type { PSC_TYPE_VMMAP, PSC_TYPE_GROUPS, PSC_TYPE_UMASK, + PSC_TYPE_RLIMIT, }; struct procstat_core; diff --git a/lib/libprocstat/libprocstat.3 b/lib/libprocstat/libprocstat.3 index 06a66a06bca0..bc78d684d7db 100644 --- a/lib/libprocstat/libprocstat.3 +++ b/lib/libprocstat/libprocstat.3 @@ -128,6 +128,13 @@ .Fa "unsigned int *count" .Fc .Ft "int" +.Fo procstat_getrlimit +.Fa "struct procstat *procstat" +.Fa "struct kinfo_proc *kp" +.Fa "int which" +.Fa "struct rlimit* rlimit" +.Fc +.Ft "int" .Fo procstat_getumask .Fa "struct procstat *procstat" .Fa "struct kinfo_proc *kp" @@ -261,6 +268,16 @@ The caller is responsible to free the allocated memory with a subsequent function call. .Pp The +.Fn procstat_getrlimit +function gets a pointer to the +.Vt procstat +structure, a pointer to +.Vt kinfo_proc +structure, resource index +.Fa which , +and returns the actual resource limit in the 4th reference parameter. +.Pp +The .Fn procstat_getumask function gets a pointer to the .Vt procstat diff --git a/lib/libprocstat/libprocstat.c b/lib/libprocstat/libprocstat.c index 1ee0f973bebc..04c10580916b 100644 --- a/lib/libprocstat/libprocstat.c +++ b/lib/libprocstat/libprocstat.c @@ -37,6 +37,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include #include @@ -135,6 +136,10 @@ static int procstat_get_vnode_info_sysctl(struct filestat *fst, static gid_t *procstat_getgroups_core(struct procstat_core *core, unsigned int *count); static gid_t *procstat_getgroups_sysctl(pid_t pid, unsigned int *count); +static int procstat_getrlimit_core(struct procstat_core *core, int which, + struct rlimit* rlimit); +static int procstat_getrlimit_sysctl(pid_t pid, int which, + struct rlimit* rlimit); static int procstat_getumask_core(struct procstat_core *core, unsigned short *maskp); static int procstat_getumask_sysctl(pid_t pid, unsigned short *maskp); @@ -1712,3 +1717,66 @@ procstat_getumask(struct procstat *procstat, struct kinfo_proc *kp, return (-1); } } + +static int +procstat_getrlimit_sysctl(pid_t pid, int which, struct rlimit* rlimit) +{ + int error, name[5]; + size_t len; + + name[0] = CTL_KERN; + name[1] = KERN_PROC; + name[2] = KERN_PROC_RLIMIT; + name[3] = pid; + name[4] = which; + len = sizeof(struct rlimit); + error = sysctl(name, 5, rlimit, &len, NULL, 0); + if (error < 0 && errno != ESRCH) { + warn("sysctl: kern.proc.rlimit: %d", pid); + return (-1); + } + if (error < 0 || len != sizeof(struct rlimit)) + return (-1); + return (0); +} + +static int +procstat_getrlimit_core(struct procstat_core *core, int which, + struct rlimit* rlimit) +{ + size_t len; + struct rlimit* rlimits; + + if (which < 0 || which >= RLIM_NLIMITS) { + errno = EINVAL; + warn("getrlimit: which"); + return (-1); + } + rlimits = procstat_core_get(core, PSC_TYPE_RLIMIT, NULL, &len); + if (rlimits == NULL) + return (-1); + if (len < sizeof(struct rlimit) * RLIM_NLIMITS) { + free(rlimits); + return (-1); + } + *rlimit = rlimits[which]; + return (0); +} + +int +procstat_getrlimit(struct procstat *procstat, struct kinfo_proc *kp, int which, + struct rlimit* rlimit) +{ + switch(procstat->type) { + case PROCSTAT_KVM: + warnx("kvm method is not supported"); + return (-1); + case PROCSTAT_SYSCTL: + return (procstat_getrlimit_sysctl(kp->ki_pid, which, rlimit)); + case PROCSTAT_CORE: + return (procstat_getrlimit_core(procstat->core, which, rlimit)); + default: + warnx("unknown access method: %d", procstat->type); + return (-1); + } +} diff --git a/lib/libprocstat/libprocstat.h b/lib/libprocstat/libprocstat.h index 8d14d0fa8936..05046af06373 100644 --- a/lib/libprocstat/libprocstat.h +++ b/lib/libprocstat/libprocstat.h @@ -91,6 +91,7 @@ struct kinfo_vmentry; struct procstat; +struct rlimit; struct filestat { int fs_type; /* Descriptor type. */ int fs_flags; /* filestat specific flags. */ @@ -170,6 +171,8 @@ gid_t *procstat_getgroups(struct procstat *procstat, struct kinfo_proc *kp, unsigned int *count); int procstat_getumask(struct procstat *procstat, struct kinfo_proc *kp, unsigned short* umask); +int procstat_getrlimit(struct procstat *procstat, struct kinfo_proc *kp, + int which, struct rlimit* rlimit); struct kinfo_vmentry *procstat_getvmmap(struct procstat *procstat, struct kinfo_proc *kp, unsigned int *count); struct procstat *procstat_open_core(const char *filename); -- cgit v1.3 From 4cdf9796417c68c0f3cbd97a751a822202db0ffd Mon Sep 17 00:00:00 2001 From: Mikolaj Golub Date: Sat, 20 Apr 2013 08:02:43 +0000 Subject: Add procstat_getpathname function to retrieve a process executable. MFC after: 1 month --- lib/libprocstat/Symbol.map | 1 + lib/libprocstat/libprocstat.3 | 20 +++++++++++++ lib/libprocstat/libprocstat.c | 65 +++++++++++++++++++++++++++++++++++++++++++ lib/libprocstat/libprocstat.h | 6 ++-- 4 files changed, 90 insertions(+), 2 deletions(-) (limited to 'lib/libprocstat') diff --git a/lib/libprocstat/Symbol.map b/lib/libprocstat/Symbol.map index 461d32058ba1..c4db0f38d6f5 100644 --- a/lib/libprocstat/Symbol.map +++ b/lib/libprocstat/Symbol.map @@ -20,6 +20,7 @@ FBSD_1.3 { procstat_freevmmap; procstat_get_shm_info; procstat_getgroups; + procstat_getpathname; procstat_getrlimit; procstat_getumask; procstat_getvmmap; diff --git a/lib/libprocstat/libprocstat.3 b/lib/libprocstat/libprocstat.3 index bc78d684d7db..fd843cbc213b 100644 --- a/lib/libprocstat/libprocstat.3 +++ b/lib/libprocstat/libprocstat.3 @@ -34,6 +34,7 @@ .Nm procstat_close , .Nm procstat_getfiles , .Nm procstat_getgroups , +.Nm procstat_getpathname , .Nm procstat_getprocs , .Nm procstat_getumask , .Nm procstat_getvmmap , @@ -128,6 +129,13 @@ .Fa "unsigned int *count" .Fc .Ft "int" +.Fo procstat_getpathname +.Fa "struct procstat *procstat" +.Fa "struct kinfo_proc *kp" +.Fa "char *pathname" +.Fa "size_t maxlen" +.Fc +.Ft "int" .Fo procstat_getrlimit .Fa "struct procstat *procstat" .Fa "struct kinfo_proc *kp" @@ -268,6 +276,18 @@ The caller is responsible to free the allocated memory with a subsequent function call. .Pp The +.Fn procstat_getpathname +function gets a pointer to the +.Vt procstat +structure, a pointer to +.Vt kinfo_proc +structure, and copies the path of the process executable to +.Fa pathname +buffer, limiting to +.Fa maxlen +characters. +.Pp +The .Fn procstat_getrlimit function gets a pointer to the .Vt procstat diff --git a/lib/libprocstat/libprocstat.c b/lib/libprocstat/libprocstat.c index 04c10580916b..e469f8eea911 100644 --- a/lib/libprocstat/libprocstat.c +++ b/lib/libprocstat/libprocstat.c @@ -136,6 +136,10 @@ static int procstat_get_vnode_info_sysctl(struct filestat *fst, static gid_t *procstat_getgroups_core(struct procstat_core *core, unsigned int *count); static gid_t *procstat_getgroups_sysctl(pid_t pid, unsigned int *count); +static int procstat_getpathname_core(struct procstat_core *core, + char *pathname, size_t maxlen); +static int procstat_getpathname_sysctl(pid_t pid, char *pathname, + size_t maxlen); static int procstat_getrlimit_core(struct procstat_core *core, int which, struct rlimit* rlimit); static int procstat_getrlimit_sysctl(pid_t pid, int which, @@ -1780,3 +1784,64 @@ procstat_getrlimit(struct procstat *procstat, struct kinfo_proc *kp, int which, return (-1); } } + +static int +procstat_getpathname_sysctl(pid_t pid, char *pathname, size_t maxlen) +{ + int error, name[4]; + size_t len; + + name[0] = CTL_KERN; + name[1] = KERN_PROC; + name[2] = KERN_PROC_PATHNAME; + name[3] = pid; + len = maxlen; + error = sysctl(name, 4, pathname, &len, NULL, 0); + if (error != 0 && errno != ESRCH) + warn("sysctl: kern.proc.pathname: %d", pid); + if (len == 0) + pathname[0] = '\0'; + return (error); +} + +static int +procstat_getpathname_core(struct procstat_core *core, char *pathname, + size_t maxlen) +{ + struct kinfo_file *files; + int cnt, i, result; + + files = kinfo_getfile_core(core, &cnt); + if (files == NULL) + return (-1); + result = -1; + for (i = 0; i < cnt; i++) { + if (files[i].kf_fd != KF_FD_TYPE_TEXT) + continue; + strncpy(pathname, files[i].kf_path, maxlen); + result = 0; + break; + } + free(files); + return (result); +} + +int +procstat_getpathname(struct procstat *procstat, struct kinfo_proc *kp, + char *pathname, size_t maxlen) +{ + switch(procstat->type) { + case PROCSTAT_KVM: + warnx("kvm method is not supported"); + return (-1); + case PROCSTAT_SYSCTL: + return (procstat_getpathname_sysctl(kp->ki_pid, pathname, + maxlen)); + case PROCSTAT_CORE: + return (procstat_getpathname_core(procstat->core, pathname, + maxlen)); + default: + warnx("unknown access method: %d", procstat->type); + return (-1); + } +} diff --git a/lib/libprocstat/libprocstat.h b/lib/libprocstat/libprocstat.h index 05046af06373..24826ece09d4 100644 --- a/lib/libprocstat/libprocstat.h +++ b/lib/libprocstat/libprocstat.h @@ -169,10 +169,12 @@ int procstat_get_vnode_info(struct procstat *procstat, struct filestat *fst, struct vnstat *vn, char *errbuf); gid_t *procstat_getgroups(struct procstat *procstat, struct kinfo_proc *kp, unsigned int *count); -int procstat_getumask(struct procstat *procstat, struct kinfo_proc *kp, - unsigned short* umask); +int procstat_getpathname(struct procstat *procstat, struct kinfo_proc *kp, + char *pathname, size_t maxlen); int procstat_getrlimit(struct procstat *procstat, struct kinfo_proc *kp, int which, struct rlimit* rlimit); +int procstat_getumask(struct procstat *procstat, struct kinfo_proc *kp, + unsigned short* umask); struct kinfo_vmentry *procstat_getvmmap(struct procstat *procstat, struct kinfo_proc *kp, unsigned int *count); struct procstat *procstat_open_core(const char *filename); -- cgit v1.3 From eec6cb1cf20290299c34bcab79119823f6ac7a1f Mon Sep 17 00:00:00 2001 From: Mikolaj Golub Date: Sat, 20 Apr 2013 08:03:56 +0000 Subject: Add procstat_getosrel function to retrieve a process osrel info. MFC after: 1 month --- lib/libprocstat/Symbol.map | 1 + lib/libprocstat/core.c | 4 ++++ lib/libprocstat/core.h | 1 + lib/libprocstat/libprocstat.3 | 14 ++++++++++++ lib/libprocstat/libprocstat.c | 52 +++++++++++++++++++++++++++++++++++++++++++ lib/libprocstat/libprocstat.h | 2 ++ 6 files changed, 74 insertions(+) (limited to 'lib/libprocstat') diff --git a/lib/libprocstat/Symbol.map b/lib/libprocstat/Symbol.map index c4db0f38d6f5..569c6f475a2c 100644 --- a/lib/libprocstat/Symbol.map +++ b/lib/libprocstat/Symbol.map @@ -20,6 +20,7 @@ FBSD_1.3 { procstat_freevmmap; procstat_get_shm_info; procstat_getgroups; + procstat_getosrel; procstat_getpathname; procstat_getrlimit; procstat_getumask; diff --git a/lib/libprocstat/core.c b/lib/libprocstat/core.c index 2ff3975f69b7..e7502227c58f 100644 --- a/lib/libprocstat/core.c +++ b/lib/libprocstat/core.c @@ -179,6 +179,10 @@ procstat_core_get(struct procstat_core *core, enum psc_type type, void *buf, n_type = NT_PROCSTAT_RLIMIT; structsize = sizeof(struct rlimit) * RLIM_NLIMITS; break; + case PSC_TYPE_OSREL: + n_type = NT_PROCSTAT_OSREL; + structsize = sizeof(int); + break; default: warnx("unknown core stat type: %d", type); return (NULL); diff --git a/lib/libprocstat/core.h b/lib/libprocstat/core.h index 967c1930c084..4d572b15b3bd 100644 --- a/lib/libprocstat/core.h +++ b/lib/libprocstat/core.h @@ -36,6 +36,7 @@ enum psc_type { PSC_TYPE_GROUPS, PSC_TYPE_UMASK, PSC_TYPE_RLIMIT, + PSC_TYPE_OSREL, }; struct procstat_core; diff --git a/lib/libprocstat/libprocstat.3 b/lib/libprocstat/libprocstat.3 index fd843cbc213b..9fecf87791f1 100644 --- a/lib/libprocstat/libprocstat.3 +++ b/lib/libprocstat/libprocstat.3 @@ -34,6 +34,7 @@ .Nm procstat_close , .Nm procstat_getfiles , .Nm procstat_getgroups , +.Nm procstat_getosrel , .Nm procstat_getpathname , .Nm procstat_getprocs , .Nm procstat_getumask , @@ -120,6 +121,11 @@ .Fa "struct procstat *procstat" .Fa "struct kinfo_proc *kp" .Fa "unsigned int *count" +.Ft int +.Fo procstat_getosrel +.Fa "struct procstat *procstat" +.Fa "struct kinfo_proc *kp" +.Fa "int *osrelp" .Fc .Ft "struct kinfo_proc *" .Fo procstat_getprocs @@ -276,6 +282,14 @@ The caller is responsible to free the allocated memory with a subsequent function call. .Pp The +.Fn procstat_getosrel +function gets a pointer to the +.Vt procstat +structure, a pointer to +.Vt kinfo_proc +structure, and returns osrel date in the 3rd reference parameter. +.Pp +The .Fn procstat_getpathname function gets a pointer to the .Vt procstat diff --git a/lib/libprocstat/libprocstat.c b/lib/libprocstat/libprocstat.c index e469f8eea911..6a71bf4d706f 100644 --- a/lib/libprocstat/libprocstat.c +++ b/lib/libprocstat/libprocstat.c @@ -1845,3 +1845,55 @@ procstat_getpathname(struct procstat *procstat, struct kinfo_proc *kp, return (-1); } } + +static int +procstat_getosrel_sysctl(pid_t pid, int *osrelp) +{ + int error, name[4]; + size_t len; + + name[0] = CTL_KERN; + name[1] = KERN_PROC; + name[2] = KERN_PROC_OSREL; + name[3] = pid; + len = sizeof(*osrelp); + error = sysctl(name, 4, osrelp, &len, NULL, 0); + if (error != 0 && errno != ESRCH) + warn("sysctl: kern.proc.osrel: %d", pid); + return (error); +} + +static int +procstat_getosrel_core(struct procstat_core *core, int *osrelp) +{ + size_t len; + int *buf; + + buf = procstat_core_get(core, PSC_TYPE_OSREL, NULL, &len); + if (buf == NULL) + return (-1); + if (len < sizeof(*osrelp)) { + free(buf); + return (-1); + } + *osrelp = *buf; + free(buf); + return (0); +} + +int +procstat_getosrel(struct procstat *procstat, struct kinfo_proc *kp, int *osrelp) +{ + switch(procstat->type) { + case PROCSTAT_KVM: + warnx("kvm method is not supported"); + return (-1); + case PROCSTAT_SYSCTL: + return (procstat_getosrel_sysctl(kp->ki_pid, osrelp)); + case PROCSTAT_CORE: + return (procstat_getosrel_core(procstat->core, osrelp)); + default: + warnx("unknown access method: %d", procstat->type); + return (-1); + } +} diff --git a/lib/libprocstat/libprocstat.h b/lib/libprocstat/libprocstat.h index 24826ece09d4..353948b647ee 100644 --- a/lib/libprocstat/libprocstat.h +++ b/lib/libprocstat/libprocstat.h @@ -169,6 +169,8 @@ int procstat_get_vnode_info(struct procstat *procstat, struct filestat *fst, struct vnstat *vn, char *errbuf); gid_t *procstat_getgroups(struct procstat *procstat, struct kinfo_proc *kp, unsigned int *count); +int procstat_getosrel(struct procstat *procstat, struct kinfo_proc *kp, + int *osrelp); int procstat_getpathname(struct procstat *procstat, struct kinfo_proc *kp, char *pathname, size_t maxlen); int procstat_getrlimit(struct procstat *procstat, struct kinfo_proc *kp, -- cgit v1.3 From 4482b5e320803848ddb826e071a17bae7148e1a8 Mon Sep 17 00:00:00 2001 From: Mikolaj Golub Date: Sat, 20 Apr 2013 08:07:04 +0000 Subject: Extend libprocstat with functions to retrieve process command line arguments and environment variables. Suggested by: stas Reviewed by: jhb and stas (initial version) MFC after: 1 month --- lib/libprocstat/Symbol.map | 4 + lib/libprocstat/core.c | 150 +++++++++++++++++++++++++++ lib/libprocstat/core.h | 3 + lib/libprocstat/libprocstat.3 | 70 +++++++++++++ lib/libprocstat/libprocstat.c | 178 +++++++++++++++++++++++++++++++++ lib/libprocstat/libprocstat.h | 6 ++ lib/libprocstat/libprocstat_internal.h | 2 + 7 files changed, 413 insertions(+) (limited to 'lib/libprocstat') diff --git a/lib/libprocstat/Symbol.map b/lib/libprocstat/Symbol.map index 569c6f475a2c..f2632c29883c 100644 --- a/lib/libprocstat/Symbol.map +++ b/lib/libprocstat/Symbol.map @@ -16,9 +16,13 @@ FBSD_1.2 { }; FBSD_1.3 { + procstat_freeargv; + procstat_freeenvv; procstat_freegroups; procstat_freevmmap; procstat_get_shm_info; + procstat_getargv; + procstat_getenvv; procstat_getgroups; procstat_getosrel; procstat_getpathname; diff --git a/lib/libprocstat/core.c b/lib/libprocstat/core.c index e7502227c58f..72dee88604d8 100644 --- a/lib/libprocstat/core.c +++ b/lib/libprocstat/core.c @@ -28,6 +28,7 @@ #include #include +#include #include #include @@ -56,6 +57,10 @@ struct procstat_core static bool core_offset(struct procstat_core *core, off_t offset); static bool core_read(struct procstat_core *core, void *buf, size_t len); +static ssize_t core_read_mem(struct procstat_core *core, void *buf, + size_t len, vm_offset_t addr, bool readall); +static void *get_args(struct procstat_core *core, vm_offset_t psstrings, + enum psc_type type, void *buf, size_t *lenp); struct procstat_core * procstat_core_open(const char *filename) @@ -146,6 +151,7 @@ procstat_core_get(struct procstat_core *core, enum psc_type type, void *buf, { Elf_Note nhdr; off_t offset, eoffset; + vm_offset_t psstrings; void *freebuf; size_t len; u_int32_t n_type; @@ -183,6 +189,12 @@ procstat_core_get(struct procstat_core *core, enum psc_type type, void *buf, n_type = NT_PROCSTAT_OSREL; structsize = sizeof(int); break; + case PSC_TYPE_PSSTRINGS: + case PSC_TYPE_ARGV: + case PSC_TYPE_ENVV: + n_type = NT_PROCSTAT_PSSTRINGS; + structsize = sizeof(vm_offset_t); + break; default: warnx("unknown core stat type: %d", type); return (NULL); @@ -238,6 +250,19 @@ procstat_core_get(struct procstat_core *core, enum psc_type type, void *buf, free(freebuf); return (NULL); } + if (type == PSC_TYPE_ARGV || type == PSC_TYPE_ENVV) { + if (len < sizeof(psstrings)) { + free(freebuf); + return (NULL); + } + psstrings = *(vm_offset_t *)buf; + if (freebuf == NULL) + len = *lenp; + else + buf = NULL; + free(freebuf); + buf = get_args(core, psstrings, type, buf, &len); + } *lenp = len; return (buf); } @@ -276,3 +301,128 @@ core_read(struct procstat_core *core, void *buf, size_t len) } return (true); } + +static ssize_t +core_read_mem(struct procstat_core *core, void *buf, size_t len, + vm_offset_t addr, bool readall) +{ + GElf_Phdr phdr; + off_t offset; + int i; + + assert(core->pc_magic == PROCSTAT_CORE_MAGIC); + + for (i = 0; i < core->pc_ehdr.e_phnum; i++) { + if (gelf_getphdr(core->pc_elf, i, &phdr) != &phdr) { + warnx("gelf_getphdr: %s", elf_errmsg(-1)); + return (-1); + } + if (phdr.p_type != PT_LOAD) + continue; + if (addr < phdr.p_vaddr || addr > phdr.p_vaddr + phdr.p_memsz) + continue; + offset = phdr.p_offset + (addr - phdr.p_vaddr); + if ((phdr.p_vaddr + phdr.p_memsz) - addr < len) { + if (readall) { + warnx("format error: " + "attempt to read out of segment"); + return (-1); + } + len = (phdr.p_vaddr + phdr.p_memsz) - addr; + } + if (!core_offset(core, offset)) + return (-1); + if (!core_read(core, buf, len)) + return (-1); + return (len); + } + warnx("format error: address %ju not found", (uintmax_t)addr); + return (-1); +} + +#define ARGS_CHUNK_SZ 256 /* Chunk size (bytes) for get_args operations. */ + +static void * +get_args(struct procstat_core *core, vm_offset_t psstrings, enum psc_type type, + void *args, size_t *lenp) +{ + struct ps_strings pss; + void *freeargs; + vm_offset_t addr; + char **argv, *p; + size_t chunksz, done, len, nchr, size; + ssize_t n; + u_int i, nstr; + + assert(type == PSC_TYPE_ARGV || type == PSC_TYPE_ENVV); + + if (core_read_mem(core, &pss, sizeof(pss), psstrings, true) == -1) + return (NULL); + if (type == PSC_TYPE_ARGV) { + addr = (vm_offset_t)pss.ps_argvstr; + nstr = pss.ps_nargvstr; + } else /* type == PSC_TYPE_ENVV */ { + addr = (vm_offset_t)pss.ps_envstr; + nstr = pss.ps_nenvstr; + } + if (addr == 0 || nstr == 0) + return (NULL); + if (nstr > ARG_MAX) { + warnx("format error"); + return (NULL); + } + size = nstr * sizeof(char *); + argv = malloc(size); + if (argv == NULL) { + warn("malloc(%zu)", size); + return (NULL); + } + done = 0; + freeargs = NULL; + if (core_read_mem(core, argv, size, addr, true) == -1) + goto fail; + if (args != NULL) { + nchr = MIN(ARG_MAX, *lenp); + } else { + nchr = ARG_MAX; + freeargs = args = malloc(nchr); + if (args == NULL) { + warn("malloc(%zu)", nchr); + goto fail; + } + } + p = args; + for (i = 0; ; i++) { + if (i == nstr) + goto done; + /* + * The program may have scribbled into its argv array, e.g. to + * remove some arguments. If that has happened, break out + * before trying to read from NULL. + */ + if (argv[i] == NULL) + goto done; + for (addr = (vm_offset_t)argv[i]; ; addr += chunksz) { + chunksz = MIN(ARGS_CHUNK_SZ, nchr - 1 - done); + if (chunksz <= 0) + goto done; + n = core_read_mem(core, p, chunksz, addr, false); + if (n == -1) + goto fail; + len = strnlen(p, chunksz); + p += len; + done += len; + if (len != chunksz) + break; + } + *p++ = '\0'; + done++; + } +fail: + free(freeargs); + args = NULL; +done: + *lenp = done; + free(argv); + return (args); +} diff --git a/lib/libprocstat/core.h b/lib/libprocstat/core.h index 4d572b15b3bd..23611486e5f0 100644 --- a/lib/libprocstat/core.h +++ b/lib/libprocstat/core.h @@ -37,6 +37,9 @@ enum psc_type { PSC_TYPE_UMASK, PSC_TYPE_RLIMIT, PSC_TYPE_OSREL, + PSC_TYPE_PSSTRINGS, + PSC_TYPE_ARGV, + PSC_TYPE_ENVV, }; struct procstat_core; diff --git a/lib/libprocstat/libprocstat.3 b/lib/libprocstat/libprocstat.3 index 9fecf87791f1..e1dc9879cc3a 100644 --- a/lib/libprocstat/libprocstat.3 +++ b/lib/libprocstat/libprocstat.3 @@ -32,6 +32,8 @@ .Nm procstat_open_kvm , .Nm procstat_open_sysctl , .Nm procstat_close , +.Nm procstat_getargv , +.Nm procstat_getenvv , .Nm procstat_getfiles , .Nm procstat_getgroups , .Nm procstat_getosrel , @@ -39,6 +41,8 @@ .Nm procstat_getprocs , .Nm procstat_getumask , .Nm procstat_getvmmap , +.Nm procstat_freeargv , +.Nm procstat_freeenvv , .Nm procstat_freefiles , .Nm procstat_freegroups , .Nm procstat_freeprocs , @@ -59,6 +63,14 @@ .Fn procstat_close "struct procstat *procstat" .Fc .Ft void +.Fo procstat_freeargv +.Fa "struct procstat *procstat" +.Fc +.Ft void +.Fo procstat_freeenvv +.Fa "struct procstat *procstat" +.Fc +.Ft void .Fo procstat_freefiles .Fa "struct procstat *procstat" .Fa "struct filestat_list *head" @@ -110,6 +122,20 @@ .Fa "struct vnstat *vn" .Fa "char *errbuf" .Fc +.Ft "char **" +.Fo procstat_getargv +.Fa "struct procstat *procstat" +.Fa "const struct kinfo_proc *kp" +.Fa "size_t nchr" +.Fa "char *errbuf" +.Fc +.Ft "char **" +.Fo procstat_getenvv +.Fa "struct procstat *procstat" +.Fa "const struct kinfo_proc *kp" +.Fa "size_t nchr" +.Fa "char *errbuf" +.Fc .Ft "struct filestat_list *" .Fo procstat_getfiles .Fa "struct procstat *procstat" @@ -251,6 +277,50 @@ The caller is responsible to free the allocated memory with a subsequent function call. .Pp The +.Fn procstat_getargv +function gets a pointer to the +.Vt procstat +structure from one of the +.Fn procstat_open_* +functions, a pointer to +.Vt kinfo_proc +structure from the array obtained from the +.Fn kvm_getprocs +function, and returns a null-terminated argument vector that corresponds to +the command line arguments passed to the process. +The +.Fa nchr +argument indicates the maximum number of characters, including null bytes, +to use in building the strings. +If this amount is exceeded, the string causing the overflow is truncated and +the partial result is returned. +This is handy for programs that print only a one line summary of a +command and should not copy out large amounts of text only to ignore it. +If +.Fa nchr +is zero, no limit is imposed and all argument strings are returned. +The values of the returned argument vector refer the strings stored +in the +.Vt procstat +internal buffer. +A subsequent call of the function with the same +.Vt procstat +argument will reuse the buffer. +To free the allocated memory +.Fn procstat_freeargv +function call can be used, or it will be released on +.Fn procstat_close . +.Pp +The +.Fn procstat_getenvv +function is similar to +.Fn procstat_getargv +but returns the vector of environment strings. +The caller may free the allocated memory with a subsequent +.Fn procstat_freeenv +function call. +.Pp +The .Fn procstat_getfiles function gets a pointer to the .Vt procstat diff --git a/lib/libprocstat/libprocstat.c b/lib/libprocstat/libprocstat.c index 6a71bf4d706f..52b9409e7573 100644 --- a/lib/libprocstat/libprocstat.c +++ b/lib/libprocstat/libprocstat.c @@ -105,6 +105,8 @@ int statfs(const char *, struct statfs *); /* XXX */ #define PROCSTAT_SYSCTL 2 #define PROCSTAT_CORE 3 +static char **getargv(struct procstat *procstat, struct kinfo_proc *kp, + size_t nchr, int env); static char *getmnton(kvm_t *kd, struct mount *m); static struct kinfo_vmentry * kinfo_getvmmap_core(struct procstat_core *core, int *cntp); @@ -158,6 +160,8 @@ procstat_close(struct procstat *procstat) kvm_close(procstat->kd); else if (procstat->type == PROCSTAT_CORE) procstat_core_close(procstat->core); + procstat_freeargv(procstat); + procstat_freeenvv(procstat); free(procstat); } @@ -1524,6 +1528,180 @@ getmnton(kvm_t *kd, struct mount *m) return (mt->mntonname); } +/* + * Auxiliary structures and functions to get process environment or + * command line arguments. + */ +struct argvec { + char *buf; + size_t bufsize; + char **argv; + size_t argc; +}; + +static struct argvec * +argvec_alloc(size_t bufsize) +{ + struct argvec *av; + + av = malloc(sizeof(*av)); + if (av == NULL) + return (NULL); + av->bufsize = bufsize; + av->buf = malloc(av->bufsize); + if (av->buf == NULL) { + free(av); + return (NULL); + } + av->argc = 32; + av->argv = malloc(sizeof(char *) * av->argc); + if (av->argv == NULL) { + free(av->buf); + free(av); + return (NULL); + } + return av; +} + +static void +argvec_free(struct argvec * av) +{ + + free(av->argv); + free(av->buf); + free(av); +} + +static char ** +getargv(struct procstat *procstat, struct kinfo_proc *kp, size_t nchr, int env) +{ + int error, name[4], argc, i; + struct argvec *av, **avp; + enum psc_type type; + size_t len; + char *p, **argv; + + assert(procstat); + assert(kp); + if (procstat->type == PROCSTAT_KVM) { + warnx("can't use kvm access method"); + return (NULL); + } + if (procstat->type != PROCSTAT_SYSCTL && + procstat->type != PROCSTAT_CORE) { + warnx("unknown access method: %d", procstat->type); + return (NULL); + } + + if (nchr == 0 || nchr > ARG_MAX) + nchr = ARG_MAX; + + avp = (struct argvec **)(env ? &procstat->argv : &procstat->envv); + av = *avp; + + if (av == NULL) + { + av = argvec_alloc(nchr); + if (av == NULL) + { + warn("malloc(%zu)", nchr); + return (NULL); + } + *avp = av; + } else if (av->bufsize < nchr) { + av->buf = reallocf(av->buf, nchr); + if (av->buf == NULL) { + warn("malloc(%zu)", nchr); + return (NULL); + } + } + if (procstat->type == PROCSTAT_SYSCTL) { + name[0] = CTL_KERN; + name[1] = KERN_PROC; + name[2] = env ? KERN_PROC_ENV : KERN_PROC_ARGS; + name[3] = kp->ki_pid; + len = nchr; + error = sysctl(name, 4, av->buf, &len, NULL, 0); + if (error != 0 && errno != ESRCH && errno != EPERM) + warn("sysctl(kern.proc.%s)", env ? "env" : "args"); + if (error != 0 || len == 0) + return (NULL); + } else /* procstat->type == PROCSTAT_CORE */ { + type = env ? PSC_TYPE_ENVV : PSC_TYPE_ARGV; + len = nchr; + if (procstat_core_get(procstat->core, type, av->buf, &len) + == NULL) { + return (NULL); + } + } + + argv = av->argv; + argc = av->argc; + i = 0; + for (p = av->buf; p < av->buf + len; p += strlen(p) + 1) { + argv[i++] = p; + if (i < argc) + continue; + /* Grow argv. */ + argc += argc; + argv = realloc(argv, sizeof(char *) * argc); + if (argv == NULL) { + warn("malloc(%zu)", sizeof(char *) * argc); + return (NULL); + } + av->argv = argv; + av->argc = argc; + } + argv[i] = NULL; + + return (argv); +} + +/* + * Return process command line arguments. + */ +char ** +procstat_getargv(struct procstat *procstat, struct kinfo_proc *p, size_t nchr) +{ + + return (getargv(procstat, p, nchr, 0)); +} + +/* + * Free the buffer allocated by procstat_getargv(). + */ +void +procstat_freeargv(struct procstat *procstat) +{ + + if (procstat->argv != NULL) { + argvec_free(procstat->argv); + procstat->argv = NULL; + } +} + +/* + * Return process environment. + */ +char ** +procstat_getenvv(struct procstat *procstat, struct kinfo_proc *p, size_t nchr) +{ + + return (getargv(procstat, p, nchr, 1)); +} + +/* + * Free the buffer allocated by procstat_getenvv(). + */ +void +procstat_freeenvv(struct procstat *procstat) +{ + if (procstat->envv != NULL) { + argvec_free(procstat->envv); + procstat->envv = NULL; + } +} + static struct kinfo_vmentry * kinfo_getvmmap_core(struct procstat_core *core, int *cntp) { diff --git a/lib/libprocstat/libprocstat.h b/lib/libprocstat/libprocstat.h index 353948b647ee..b7719c01ff3e 100644 --- a/lib/libprocstat/libprocstat.h +++ b/lib/libprocstat/libprocstat.h @@ -147,6 +147,8 @@ STAILQ_HEAD(filestat_list, filestat); __BEGIN_DECLS void procstat_close(struct procstat *procstat); +void procstat_freeargv(struct procstat *procstat); +void procstat_freeenvv(struct procstat *procstat); void procstat_freegroups(struct procstat *procstat, gid_t *groups); void procstat_freeprocs(struct procstat *procstat, struct kinfo_proc *p); void procstat_freefiles(struct procstat *procstat, @@ -167,6 +169,10 @@ int procstat_get_socket_info(struct procstat *procstat, struct filestat *fst, struct sockstat *sock, char *errbuf); int procstat_get_vnode_info(struct procstat *procstat, struct filestat *fst, struct vnstat *vn, char *errbuf); +char **procstat_getargv(struct procstat *procstat, struct kinfo_proc *p, + size_t nchr); +char **procstat_getenvv(struct procstat *procstat, struct kinfo_proc *p, + size_t nchr); gid_t *procstat_getgroups(struct procstat *procstat, struct kinfo_proc *kp, unsigned int *count); int procstat_getosrel(struct procstat *procstat, struct kinfo_proc *kp, diff --git a/lib/libprocstat/libprocstat_internal.h b/lib/libprocstat/libprocstat_internal.h index ff1e742f4611..6ca3197cbc4e 100644 --- a/lib/libprocstat/libprocstat_internal.h +++ b/lib/libprocstat/libprocstat_internal.h @@ -34,6 +34,8 @@ struct procstat { kvm_t *kd; void *vmentries; void *files; + void *argv; + void *envv; struct procstat_core *core; }; -- cgit v1.3 From 2ff020d3c3de8d32dc8c413d07e4b1d5fa6ee766 Mon Sep 17 00:00:00 2001 From: Mikolaj Golub Date: Sat, 20 Apr 2013 08:10:47 +0000 Subject: Add procstat_getauxv function to retrieve a process auxiliary vector. MFC after: 1 month --- lib/libprocstat/Symbol.map | 2 + lib/libprocstat/core.c | 4 ++ lib/libprocstat/core.h | 1 + lib/libprocstat/libprocstat.3 | 26 ++++++++ lib/libprocstat/libprocstat.c | 152 ++++++++++++++++++++++++++++++++++++++++++ lib/libprocstat/libprocstat.h | 15 +++++ 6 files changed, 200 insertions(+) (limited to 'lib/libprocstat') diff --git a/lib/libprocstat/Symbol.map b/lib/libprocstat/Symbol.map index f2632c29883c..322d46f1b920 100644 --- a/lib/libprocstat/Symbol.map +++ b/lib/libprocstat/Symbol.map @@ -17,11 +17,13 @@ FBSD_1.2 { FBSD_1.3 { procstat_freeargv; + procstat_freeauxv; procstat_freeenvv; procstat_freegroups; procstat_freevmmap; procstat_get_shm_info; procstat_getargv; + procstat_getauxv; procstat_getenvv; procstat_getgroups; procstat_getosrel; diff --git a/lib/libprocstat/core.c b/lib/libprocstat/core.c index 72dee88604d8..b83cdfda4cca 100644 --- a/lib/libprocstat/core.c +++ b/lib/libprocstat/core.c @@ -195,6 +195,10 @@ procstat_core_get(struct procstat_core *core, enum psc_type type, void *buf, n_type = NT_PROCSTAT_PSSTRINGS; structsize = sizeof(vm_offset_t); break; + case PSC_TYPE_AUXV: + n_type = NT_PROCSTAT_AUXV; + structsize = sizeof(Elf_Auxinfo); + break; default: warnx("unknown core stat type: %d", type); return (NULL); diff --git a/lib/libprocstat/core.h b/lib/libprocstat/core.h index 23611486e5f0..6639abce174d 100644 --- a/lib/libprocstat/core.h +++ b/lib/libprocstat/core.h @@ -40,6 +40,7 @@ enum psc_type { PSC_TYPE_PSSTRINGS, PSC_TYPE_ARGV, PSC_TYPE_ENVV, + PSC_TYPE_AUXV, }; struct procstat_core; diff --git a/lib/libprocstat/libprocstat.3 b/lib/libprocstat/libprocstat.3 index e1dc9879cc3a..5a425e727367 100644 --- a/lib/libprocstat/libprocstat.3 +++ b/lib/libprocstat/libprocstat.3 @@ -33,6 +33,7 @@ .Nm procstat_open_sysctl , .Nm procstat_close , .Nm procstat_getargv , +.Nm procstat_getauxv , .Nm procstat_getenvv , .Nm procstat_getfiles , .Nm procstat_getgroups , @@ -42,6 +43,7 @@ .Nm procstat_getumask , .Nm procstat_getvmmap , .Nm procstat_freeargv , +.Nm procstat_freeauxv , .Nm procstat_freeenvv , .Nm procstat_freefiles , .Nm procstat_freegroups , @@ -67,6 +69,11 @@ .Fa "struct procstat *procstat" .Fc .Ft void +.Fo procstat_freeauxv +.Fa "struct procstat *procstat" +.Fa "Elf_Auxinfo *auxv" +.Fc +.Ft void .Fo procstat_freeenvv .Fa "struct procstat *procstat" .Fc @@ -129,6 +136,12 @@ .Fa "size_t nchr" .Fa "char *errbuf" .Fc +.Ft "Elf_Auxinfo *" +.Fo procstat_getauxv +.Fa "struct procstat *procstat" +.Fa "struct kinfo_proc *kp" +.Fa "unsigned int *count" +.Fc .Ft "char **" .Fo procstat_getenvv .Fa "struct procstat *procstat" @@ -321,6 +334,19 @@ The caller may free the allocated memory with a subsequent function call. .Pp The +.Fn procstat_getauxv +function gets a pointer to the +.Vt procstat +structure, a pointer to +.Vt kinfo_proc +structure, and returns the auxiliary vector as a dynamically allocated array of +.Vt Elf_Auxinfo +elements. +The caller is responsible to free the allocated memory with a subsequent +.Fn procstat_freeauxv +function call. +.Pp +The .Fn procstat_getfiles function gets a pointer to the .Vt procstat diff --git a/lib/libprocstat/libprocstat.c b/lib/libprocstat/libprocstat.c index 52b9409e7573..b70586d37912 100644 --- a/lib/libprocstat/libprocstat.c +++ b/lib/libprocstat/libprocstat.c @@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$"); #include +#include #include #include #include @@ -110,6 +111,9 @@ static char **getargv(struct procstat *procstat, struct kinfo_proc *kp, static char *getmnton(kvm_t *kd, struct mount *m); static struct kinfo_vmentry * kinfo_getvmmap_core(struct procstat_core *core, int *cntp); +static Elf_Auxinfo *procstat_getauxv_core(struct procstat_core *core, + unsigned int *cntp); +static Elf_Auxinfo *procstat_getauxv_sysctl(pid_t pid, unsigned int *cntp); static struct filestat_list *procstat_getfiles_kvm( struct procstat *procstat, struct kinfo_proc *kp, int mmapped); static struct filestat_list *procstat_getfiles_sysctl( @@ -2075,3 +2079,151 @@ procstat_getosrel(struct procstat *procstat, struct kinfo_proc *kp, int *osrelp) return (-1); } } + +#define PROC_AUXV_MAX 256 + +#if __ELF_WORD_SIZE == 64 +static const char *elf32_sv_names[] = { + "Linux ELF32", + "FreeBSD ELF32", +}; + +static int +is_elf32_sysctl(pid_t pid) +{ + int error, name[4]; + size_t len, i; + static char sv_name[256]; + + name[0] = CTL_KERN; + name[1] = KERN_PROC; + name[2] = KERN_PROC_SV_NAME; + name[3] = pid; + len = sizeof(sv_name); + error = sysctl(name, 4, sv_name, &len, NULL, 0); + if (error != 0 || len == 0) + return (0); + for (i = 0; i < sizeof(elf32_sv_names) / sizeof(*elf32_sv_names); i++) { + if (strncmp(sv_name, elf32_sv_names[i], sizeof(sv_name)) == 0) + return (1); + } + return (0); +} + +static Elf_Auxinfo * +procstat_getauxv32_sysctl(pid_t pid, unsigned int *cntp) +{ + Elf_Auxinfo *auxv; + Elf32_Auxinfo *auxv32; + void *ptr; + size_t len; + unsigned int i, count; + int name[4]; + + name[0] = CTL_KERN; + name[1] = KERN_PROC; + name[2] = KERN_PROC_AUXV; + name[3] = pid; + len = PROC_AUXV_MAX * sizeof(Elf32_Auxinfo); + auxv = NULL; + auxv32 = malloc(len); + if (auxv32 == NULL) { + warn("malloc(%zu)", len); + goto out; + } + if (sysctl(name, 4, auxv32, &len, NULL, 0) == -1) { + if (errno != ESRCH && errno != EPERM) + warn("sysctl: kern.proc.auxv: %d: %d", pid, errno); + goto out; + } + count = len / sizeof(Elf_Auxinfo); + auxv = malloc(count * sizeof(Elf_Auxinfo)); + if (auxv == NULL) { + warn("malloc(%zu)", count * sizeof(Elf_Auxinfo)); + goto out; + } + for (i = 0; i < count; i++) { + /* + * XXX: We expect that values for a_type on a 32-bit platform + * are directly mapped to values on 64-bit one, which is not + * necessarily true. + */ + auxv[i].a_type = auxv32[i].a_type; + ptr = &auxv32[i].a_un; + auxv[i].a_un.a_val = *((uint32_t *)ptr); + } + *cntp = count; +out: + free(auxv32); + return (auxv); +} +#endif /* __ELF_WORD_SIZE == 64 */ + +static Elf_Auxinfo * +procstat_getauxv_sysctl(pid_t pid, unsigned int *cntp) +{ + Elf_Auxinfo *auxv; + int name[4]; + size_t len; + +#if __ELF_WORD_SIZE == 64 + if (is_elf32_sysctl(pid)) + return (procstat_getauxv32_sysctl(pid, cntp)); +#endif + name[0] = CTL_KERN; + name[1] = KERN_PROC; + name[2] = KERN_PROC_AUXV; + name[3] = pid; + len = PROC_AUXV_MAX * sizeof(Elf_Auxinfo); + auxv = malloc(len); + if (auxv == NULL) { + warn("malloc(%zu)", len); + return (NULL); + } + if (sysctl(name, 4, auxv, &len, NULL, 0) == -1) { + if (errno != ESRCH && errno != EPERM) + warn("sysctl: kern.proc.auxv: %d: %d", pid, errno); + free(auxv); + return (NULL); + } + *cntp = len / sizeof(Elf_Auxinfo); + return (auxv); +} + +static Elf_Auxinfo * +procstat_getauxv_core(struct procstat_core *core, unsigned int *cntp) +{ + Elf_Auxinfo *auxv; + size_t len; + + auxv = procstat_core_get(core, PSC_TYPE_AUXV, NULL, &len); + if (auxv == NULL) + return (NULL); + *cntp = len / sizeof(Elf_Auxinfo); + return (auxv); +} + +Elf_Auxinfo * +procstat_getauxv(struct procstat *procstat, struct kinfo_proc *kp, + unsigned int *cntp) +{ + switch(procstat->type) { + case PROCSTAT_KVM: + warnx("kvm method is not supported"); + return (NULL); + case PROCSTAT_SYSCTL: + return (procstat_getauxv_sysctl(kp->ki_pid, cntp)); + case PROCSTAT_CORE: + return (procstat_getauxv_core(procstat->core, cntp)); + default: + warnx("unknown access method: %d", procstat->type); + return (NULL); + } +} + +void +procstat_freeauxv(struct procstat *procstat __unused, Elf_Auxinfo *auxv) +{ + + free(auxv); +} diff --git a/lib/libprocstat/libprocstat.h b/lib/libprocstat/libprocstat.h index b7719c01ff3e..3ac51e138ebd 100644 --- a/lib/libprocstat/libprocstat.h +++ b/lib/libprocstat/libprocstat.h @@ -29,6 +29,14 @@ #ifndef _LIBPROCSTAT_H_ #define _LIBPROCSTAT_H_ +/* + * XXX: sys/elf.h conflicts with zfs_context.h. Workaround this by not + * including conflicting parts when building zfs code. + */ +#ifndef ZFS +#include +#endif + /* * Vnode types. */ @@ -148,6 +156,9 @@ STAILQ_HEAD(filestat_list, filestat); __BEGIN_DECLS void procstat_close(struct procstat *procstat); void procstat_freeargv(struct procstat *procstat); +#ifndef ZFS +void procstat_freeauxv(struct procstat *procstat, Elf_Auxinfo *auxv); +#endif void procstat_freeenvv(struct procstat *procstat); void procstat_freegroups(struct procstat *procstat, gid_t *groups); void procstat_freeprocs(struct procstat *procstat, struct kinfo_proc *p); @@ -171,6 +182,10 @@ int procstat_get_vnode_info(struct procstat *procstat, struct filestat *fst, struct vnstat *vn, char *errbuf); char **procstat_getargv(struct procstat *procstat, struct kinfo_proc *p, size_t nchr); +#ifndef ZFS +Elf_Auxinfo *procstat_getauxv(struct procstat *procstat, + struct kinfo_proc *kp, unsigned int *cntp); +#endif char **procstat_getenvv(struct procstat *procstat, struct kinfo_proc *p, size_t nchr); gid_t *procstat_getgroups(struct procstat *procstat, struct kinfo_proc *kp, -- cgit v1.3 From 89358231fa0e1b89c0b3c191b6cefcfc542746b7 Mon Sep 17 00:00:00 2001 From: Mikolaj Golub Date: Sat, 20 Apr 2013 08:17:20 +0000 Subject: Add procstat_getkstack function to dump kernel stacks of a process. MFC after: 1 month --- lib/libprocstat/Symbol.map | 2 ++ lib/libprocstat/libprocstat.3 | 29 ++++++++++++++++++ lib/libprocstat/libprocstat.c | 70 +++++++++++++++++++++++++++++++++++++++++++ lib/libprocstat/libprocstat.h | 5 ++++ 4 files changed, 106 insertions(+) (limited to 'lib/libprocstat') diff --git a/lib/libprocstat/Symbol.map b/lib/libprocstat/Symbol.map index 322d46f1b920..085720cf4590 100644 --- a/lib/libprocstat/Symbol.map +++ b/lib/libprocstat/Symbol.map @@ -20,12 +20,14 @@ FBSD_1.3 { procstat_freeauxv; procstat_freeenvv; procstat_freegroups; + procstat_freekstack; procstat_freevmmap; procstat_get_shm_info; procstat_getargv; procstat_getauxv; procstat_getenvv; procstat_getgroups; + procstat_getkstack; procstat_getosrel; procstat_getpathname; procstat_getrlimit; diff --git a/lib/libprocstat/libprocstat.3 b/lib/libprocstat/libprocstat.3 index 5a425e727367..136774126183 100644 --- a/lib/libprocstat/libprocstat.3 +++ b/lib/libprocstat/libprocstat.3 @@ -37,6 +37,7 @@ .Nm procstat_getenvv , .Nm procstat_getfiles , .Nm procstat_getgroups , +.Nm procstat_getkstack , .Nm procstat_getosrel , .Nm procstat_getpathname , .Nm procstat_getprocs , @@ -47,6 +48,7 @@ .Nm procstat_freeenvv , .Nm procstat_freefiles , .Nm procstat_freegroups , +.Nm procstat_freekstack , .Nm procstat_freeprocs , .Nm procstat_freevmmap , .Nm procstat_get_pipe_info , @@ -88,6 +90,11 @@ .Fa "gid_t *groups" .Fc .Ft void +.Fo procstat_freekstack +.Fa "struct procstat *procstat" +.Fa "struct kinfo_kstack *kkstp" +.Fc +.Ft void .Fn procstat_freeprocs "struct procstat *procstat" "struct kinfo_proc *p" .Ft void .Fo procstat_freevmmap @@ -166,6 +173,12 @@ .Fa "struct kinfo_proc *kp" .Fa "int *osrelp" .Fc +.Ft "struct kinfo_kstack *" +.Fo procstat_getkstack +.Fa "struct procstat *procstat" +.Fa "struct kinfo_proc *kp" +.Fa "unsigned int *count" +.Fc .Ft "struct kinfo_proc *" .Fo procstat_getprocs .Fa "struct procstat *procstat" @@ -378,6 +391,22 @@ The caller is responsible to free the allocated memory with a subsequent function call. .Pp The +.Fn procstat_getkstack +function gets a pointer to the +.Vt procstat +structure initialized with one of the +.Fn procstat_open_* +functions, a pointer to +.Vt kinfo_proc +structure, and returns kernel stacks of the process as a dynamically allocated +array of +.Vt kinfo_kstack +structures. +The caller is responsible to free the allocated memory with a subsequent +.Fn procstat_freekstack +function call. +.Pp +The .Fn procstat_getosrel function gets a pointer to the .Vt procstat diff --git a/lib/libprocstat/libprocstat.c b/lib/libprocstat/libprocstat.c index b70586d37912..a54b90d93bb3 100644 --- a/lib/libprocstat/libprocstat.c +++ b/lib/libprocstat/libprocstat.c @@ -142,6 +142,8 @@ static int procstat_get_vnode_info_sysctl(struct filestat *fst, static gid_t *procstat_getgroups_core(struct procstat_core *core, unsigned int *count); static gid_t *procstat_getgroups_sysctl(pid_t pid, unsigned int *count); +static struct kinfo_kstack *procstat_getkstack_sysctl(pid_t pid, + int *cntp); static int procstat_getpathname_core(struct procstat_core *core, char *pathname, size_t maxlen); static int procstat_getpathname_sysctl(pid_t pid, char *pathname, @@ -1764,6 +1766,7 @@ struct kinfo_vmentry * procstat_getvmmap(struct procstat *procstat, struct kinfo_proc *kp, unsigned int *cntp) { + switch(procstat->type) { case PROCSTAT_KVM: warnx("kvm method is not supported"); @@ -2227,3 +2230,70 @@ procstat_freeauxv(struct procstat *procstat __unused, Elf_Auxinfo *auxv) free(auxv); } + +static struct kinfo_kstack * +procstat_getkstack_sysctl(pid_t pid, int *cntp) +{ + struct kinfo_kstack *kkstp; + int error, name[4]; + size_t len; + + name[0] = CTL_KERN; + name[1] = KERN_PROC; + name[2] = KERN_PROC_KSTACK; + name[3] = pid; + + len = 0; + error = sysctl(name, 4, NULL, &len, NULL, 0); + if (error < 0 && errno != ESRCH && errno != EPERM && errno != ENOENT) { + warn("sysctl: kern.proc.kstack: %d", pid); + return (NULL); + } + if (error == -1 && errno == ENOENT) { + warnx("sysctl: kern.proc.kstack unavailable" + " (options DDB or options STACK required in kernel)"); + return (NULL); + } + if (error == -1) + return (NULL); + kkstp = malloc(len); + if (kkstp == NULL) { + warn("malloc(%zu)", len); + return (NULL); + } + if (sysctl(name, 4, kkstp, &len, NULL, 0) == -1) { + warn("sysctl: kern.proc.pid: %d", pid); + free(kkstp); + return (NULL); + } + *cntp = len / sizeof(*kkstp); + + return (kkstp); +} + +struct kinfo_kstack * +procstat_getkstack(struct procstat *procstat, struct kinfo_proc *kp, + unsigned int *cntp) +{ + switch(procstat->type) { + case PROCSTAT_KVM: + warnx("kvm method is not supported"); + return (NULL); + case PROCSTAT_SYSCTL: + return (procstat_getkstack_sysctl(kp->ki_pid, cntp)); + case PROCSTAT_CORE: + warnx("core method is not supported"); + return (NULL); + default: + warnx("unknown access method: %d", procstat->type); + return (NULL); + } +} + +void +procstat_freekstack(struct procstat *procstat __unused, + struct kinfo_kstack *kkstp) +{ + + free(kkstp); +} diff --git a/lib/libprocstat/libprocstat.h b/lib/libprocstat/libprocstat.h index 3ac51e138ebd..2c2662d5dbeb 100644 --- a/lib/libprocstat/libprocstat.h +++ b/lib/libprocstat/libprocstat.h @@ -97,6 +97,7 @@ #define PS_FST_FFLAG_EXEC 0x2000 #define PS_FST_FFLAG_HASLOCK 0x4000 +struct kinfo_kstack; struct kinfo_vmentry; struct procstat; struct rlimit; @@ -161,6 +162,8 @@ void procstat_freeauxv(struct procstat *procstat, Elf_Auxinfo *auxv); #endif void procstat_freeenvv(struct procstat *procstat); void procstat_freegroups(struct procstat *procstat, gid_t *groups); +void procstat_freekstack(struct procstat *procstat, + struct kinfo_kstack *kkstp); void procstat_freeprocs(struct procstat *procstat, struct kinfo_proc *p); void procstat_freefiles(struct procstat *procstat, struct filestat_list *head); @@ -190,6 +193,8 @@ char **procstat_getenvv(struct procstat *procstat, struct kinfo_proc *p, size_t nchr); gid_t *procstat_getgroups(struct procstat *procstat, struct kinfo_proc *kp, unsigned int *count); +struct kinfo_kstack *procstat_getkstack(struct procstat *procstat, + struct kinfo_proc *kp, unsigned int *count); int procstat_getosrel(struct procstat *procstat, struct kinfo_proc *kp, int *osrelp); int procstat_getpathname(struct procstat *procstat, struct kinfo_proc *kp, -- cgit v1.3 From 6dd520d6095a9fd6223b7299b38ae8d6e7644e70 Mon Sep 17 00:00:00 2001 From: Mikolaj Golub Date: Sat, 20 Apr 2013 08:25:14 +0000 Subject: Bump date. --- lib/libprocstat/libprocstat.3 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/libprocstat') diff --git a/lib/libprocstat/libprocstat.3 b/lib/libprocstat/libprocstat.3 index 136774126183..8e17f6aa2779 100644 --- a/lib/libprocstat/libprocstat.3 +++ b/lib/libprocstat/libprocstat.3 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd April 1, 2012 +.Dd April 20, 2013 .Dt LIBPROCSTAT 3 .Os .Sh NAME -- cgit v1.3 From 20ed2b43437e2ab068fbec72a7a6687bb77d4b1d Mon Sep 17 00:00:00 2001 From: Joel Dahl Date: Sat, 20 Apr 2013 22:16:49 +0000 Subject: mdoc: end function context properly. --- lib/libprocstat/libprocstat.3 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/libprocstat') diff --git a/lib/libprocstat/libprocstat.3 b/lib/libprocstat/libprocstat.3 index 8e17f6aa2779..3312427a0ed2 100644 --- a/lib/libprocstat/libprocstat.3 +++ b/lib/libprocstat/libprocstat.3 @@ -65,7 +65,6 @@ .In libprocstat.h .Ft void .Fn procstat_close "struct procstat *procstat" -.Fc .Ft void .Fo procstat_freeargv .Fa "struct procstat *procstat" @@ -167,6 +166,7 @@ .Fa "struct procstat *procstat" .Fa "struct kinfo_proc *kp" .Fa "unsigned int *count" +.Fc .Ft int .Fo procstat_getosrel .Fa "struct procstat *procstat" -- cgit v1.3 From b03e2d772987099120f10ccadedde269205cfb3c Mon Sep 17 00:00:00 2001 From: Mikolaj Golub Date: Sun, 21 Apr 2013 17:10:10 +0000 Subject: Embed revision id in the library. MFC after: 29 days --- lib/libprocstat/core.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'lib/libprocstat') diff --git a/lib/libprocstat/core.c b/lib/libprocstat/core.c index b83cdfda4cca..70ab86df5b0b 100644 --- a/lib/libprocstat/core.c +++ b/lib/libprocstat/core.c @@ -22,10 +22,11 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * - * $FreeBSD$ */ +#include +__FBSDID("$FreeBSD$"); + #include #include #include -- cgit v1.3 From 1f84c47e42cff297d9454c73ac9452fea84974cb Mon Sep 17 00:00:00 2001 From: Mikolaj Golub Date: Wed, 1 May 2013 15:01:05 +0000 Subject: KVM method support for procstat_getgroups, procstat_getumask, procstat_getrlimit, and procstat_getosrel. MFC after: 3 weeks --- lib/libprocstat/libprocstat.c | 129 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 121 insertions(+), 8 deletions(-) (limited to 'lib/libprocstat') diff --git a/lib/libprocstat/libprocstat.c b/lib/libprocstat/libprocstat.c index a54b90d93bb3..535cdfce39dc 100644 --- a/lib/libprocstat/libprocstat.c +++ b/lib/libprocstat/libprocstat.c @@ -39,6 +39,9 @@ __FBSDID("$FreeBSD$"); #include #include #include +#define _WANT_UCRED +#include +#undef _WANT_UCRED #include #include #include @@ -141,19 +144,30 @@ static int procstat_get_vnode_info_sysctl(struct filestat *fst, struct vnstat *vn, char *errbuf); static gid_t *procstat_getgroups_core(struct procstat_core *core, unsigned int *count); +static gid_t * procstat_getgroups_kvm(kvm_t *kd, struct kinfo_proc *kp, + unsigned int *count); static gid_t *procstat_getgroups_sysctl(pid_t pid, unsigned int *count); static struct kinfo_kstack *procstat_getkstack_sysctl(pid_t pid, int *cntp); +static int procstat_getosrel_core(struct procstat_core *core, + int *osrelp); +static int procstat_getosrel_kvm(kvm_t *kd, struct kinfo_proc *kp, + int *osrelp); +static int procstat_getosrel_sysctl(pid_t pid, int *osrelp); static int procstat_getpathname_core(struct procstat_core *core, char *pathname, size_t maxlen); static int procstat_getpathname_sysctl(pid_t pid, char *pathname, size_t maxlen); static int procstat_getrlimit_core(struct procstat_core *core, int which, struct rlimit* rlimit); +static int procstat_getrlimit_kvm(kvm_t *kd, struct kinfo_proc *kp, + int which, struct rlimit* rlimit); static int procstat_getrlimit_sysctl(pid_t pid, int which, struct rlimit* rlimit); static int procstat_getumask_core(struct procstat_core *core, unsigned short *maskp); +static int procstat_getumask_kvm(kvm_t *kd, struct kinfo_proc *kp, + unsigned short *maskp); static int procstat_getumask_sysctl(pid_t pid, unsigned short *maskp); static int vntype2psfsttype(int type); @@ -1789,6 +1803,46 @@ procstat_freevmmap(struct procstat *procstat __unused, free(vmmap); } +static gid_t * +procstat_getgroups_kvm(kvm_t *kd, struct kinfo_proc *kp, unsigned int *cntp) +{ + struct proc proc; + struct ucred ucred; + gid_t *groups; + size_t len; + + assert(kd != NULL); + assert(kp != NULL); + if (!kvm_read_all(kd, (unsigned long)kp->ki_paddr, &proc, + sizeof(proc))) { + warnx("can't read proc struct at %p for pid %d", + kp->ki_paddr, kp->ki_pid); + return (NULL); + } + if (proc.p_ucred == NOCRED) + return (NULL); + if (!kvm_read_all(kd, (unsigned long)proc.p_ucred, &ucred, + sizeof(ucred))) { + warnx("can't read ucred struct at %p for pid %d", + proc.p_ucred, kp->ki_pid); + return (NULL); + } + len = ucred.cr_ngroups * sizeof(gid_t); + groups = malloc(len); + if (groups == NULL) { + warn("malloc(%zu)", len); + return (NULL); + } + if (!kvm_read_all(kd, (unsigned long)ucred.cr_groups, groups, len)) { + warnx("can't read groups at %p for pid %d", + ucred.cr_groups, kp->ki_pid); + free(groups); + return (NULL); + } + *cntp = ucred.cr_ngroups; + return (groups); +} + static gid_t * procstat_getgroups_sysctl(pid_t pid, unsigned int *cntp) { @@ -1834,8 +1888,7 @@ procstat_getgroups(struct procstat *procstat, struct kinfo_proc *kp, { switch(procstat->type) { case PROCSTAT_KVM: - warnx("kvm method is not supported"); - return (NULL); + return (procstat_getgroups_kvm(procstat->kd, kp, cntp)); case PROCSTAT_SYSCTL: return (procstat_getgroups_sysctl(kp->ki_pid, cntp)); case PROCSTAT_CORE: @@ -1853,6 +1906,24 @@ procstat_freegroups(struct procstat *procstat __unused, gid_t *groups) free(groups); } +static int +procstat_getumask_kvm(kvm_t *kd, struct kinfo_proc *kp, unsigned short *maskp) +{ + struct filedesc fd; + + assert(kd != NULL); + assert(kp != NULL); + if (kp->ki_fd == NULL) + return (-1); + if (!kvm_read_all(kd, (unsigned long)kp->ki_fd, &fd, sizeof(fd))) { + warnx("can't read filedesc at %p for pid %d", kp->ki_fd, + kp->ki_pid); + return (-1); + } + *maskp = fd.fd_cmask; + return (0); +} + static int procstat_getumask_sysctl(pid_t pid, unsigned short *maskp) { @@ -1895,8 +1966,7 @@ procstat_getumask(struct procstat *procstat, struct kinfo_proc *kp, { switch(procstat->type) { case PROCSTAT_KVM: - warnx("kvm method is not supported"); - return (-1); + return (procstat_getumask_kvm(procstat->kd, kp, maskp)); case PROCSTAT_SYSCTL: return (procstat_getumask_sysctl(kp->ki_pid, maskp)); case PROCSTAT_CORE: @@ -1907,6 +1977,33 @@ procstat_getumask(struct procstat *procstat, struct kinfo_proc *kp, } } +static int +procstat_getrlimit_kvm(kvm_t *kd, struct kinfo_proc *kp, int which, + struct rlimit* rlimit) +{ + struct proc proc; + unsigned long offset; + + assert(kd != NULL); + assert(kp != NULL); + assert(which >= 0 && which < RLIM_NLIMITS); + if (!kvm_read_all(kd, (unsigned long)kp->ki_paddr, &proc, + sizeof(proc))) { + warnx("can't read proc struct at %p for pid %d", + kp->ki_paddr, kp->ki_pid); + return (-1); + } + if (proc.p_limit == NULL) + return (-1); + offset = (unsigned long)proc.p_limit + sizeof(struct rlimit) * which; + if (!kvm_read_all(kd, offset, rlimit, sizeof(*rlimit))) { + warnx("can't read rlimit struct at %p for pid %d", + (void *)offset, kp->ki_pid); + return (-1); + } + return (0); +} + static int procstat_getrlimit_sysctl(pid_t pid, int which, struct rlimit* rlimit) { @@ -1958,8 +2055,8 @@ procstat_getrlimit(struct procstat *procstat, struct kinfo_proc *kp, int which, { switch(procstat->type) { case PROCSTAT_KVM: - warnx("kvm method is not supported"); - return (-1); + return (procstat_getrlimit_kvm(procstat->kd, kp, which, + rlimit)); case PROCSTAT_SYSCTL: return (procstat_getrlimit_sysctl(kp->ki_pid, which, rlimit)); case PROCSTAT_CORE: @@ -2031,6 +2128,23 @@ procstat_getpathname(struct procstat *procstat, struct kinfo_proc *kp, } } +static int +procstat_getosrel_kvm(kvm_t *kd, struct kinfo_proc *kp, int *osrelp) +{ + struct proc proc; + + assert(kd != NULL); + assert(kp != NULL); + if (!kvm_read_all(kd, (unsigned long)kp->ki_paddr, &proc, + sizeof(proc))) { + warnx("can't read proc struct at %p for pid %d", + kp->ki_paddr, kp->ki_pid); + return (-1); + } + *osrelp = proc.p_osrel; + return (0); +} + static int procstat_getosrel_sysctl(pid_t pid, int *osrelp) { @@ -2071,8 +2185,7 @@ procstat_getosrel(struct procstat *procstat, struct kinfo_proc *kp, int *osrelp) { switch(procstat->type) { case PROCSTAT_KVM: - warnx("kvm method is not supported"); - return (-1); + return (procstat_getosrel_kvm(procstat->kd, kp, osrelp)); case PROCSTAT_SYSCTL: return (procstat_getosrel_sysctl(kp->ki_pid, osrelp)); case PROCSTAT_CORE: -- cgit v1.3 From dd70ad64bf8714ba3e6ce0df49ced3e58014cb67 Mon Sep 17 00:00:00 2001 From: Mikolaj Golub Date: Wed, 1 May 2013 15:02:58 +0000 Subject: procstat_getpathname: for kvm method, instead of returning the error that the method is not supported, return an empty string. This looks more handy for callers like procstat(1), which will not abort after the failed call and still output some useful information. MFC after: 3 weeks --- lib/libprocstat/libprocstat.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'lib/libprocstat') diff --git a/lib/libprocstat/libprocstat.c b/lib/libprocstat/libprocstat.c index 535cdfce39dc..dd16c80d1c79 100644 --- a/lib/libprocstat/libprocstat.c +++ b/lib/libprocstat/libprocstat.c @@ -2114,8 +2114,10 @@ procstat_getpathname(struct procstat *procstat, struct kinfo_proc *kp, { switch(procstat->type) { case PROCSTAT_KVM: - warnx("kvm method is not supported"); - return (-1); + /* XXX: Return empty string. */ + if (maxlen > 0) + pathname[0] = '\0'; + return (0); case PROCSTAT_SYSCTL: return (procstat_getpathname_sysctl(kp->ki_pid, pathname, maxlen)); -- cgit v1.3 From 958aa57537952c7e7018518bb9d643b81e85e827 Mon Sep 17 00:00:00 2001 From: John Baldwin Date: Fri, 3 May 2013 21:11:57 +0000 Subject: Similar to 233760 and 236717, export some more useful info about the kernel-based POSIX semaphore descriptors to userland via procstat(1) and fstat(1): - Change sem file descriptors to track the pathname they are associated with and add a ksem_info() method to copy the path out to a caller-supplied buffer. - Use the fo_stat() method of shared memory objects and ksem_info() to export the path, mode, and value of a semaphore via struct kinfo_file. - Add a struct semstat to the libprocstat(3) interface along with a procstat_get_sem_info() to export the mode and value of a semaphore. - Teach fstat about semaphores and to display their path, mode, and value. MFC after: 2 weeks --- lib/libprocstat/Symbol.map | 1 + lib/libprocstat/libprocstat.3 | 14 ++++++- lib/libprocstat/libprocstat.c | 90 +++++++++++++++++++++++++++++++++++++++++++ lib/libprocstat/libprocstat.h | 6 +++ sys/kern/kern_descrip.c | 31 +++++++++++++++ sys/kern/uipc_sem.c | 19 ++++++++- sys/sys/ksem.h | 8 +++- sys/sys/user.h | 4 ++ usr.bin/fstat/fstat.1 | 2 + usr.bin/fstat/fstat.c | 29 ++++++++++++++ 10 files changed, 201 insertions(+), 3 deletions(-) (limited to 'lib/libprocstat') diff --git a/lib/libprocstat/Symbol.map b/lib/libprocstat/Symbol.map index 085720cf4590..1495bfc28c66 100644 --- a/lib/libprocstat/Symbol.map +++ b/lib/libprocstat/Symbol.map @@ -22,6 +22,7 @@ FBSD_1.3 { procstat_freegroups; procstat_freekstack; procstat_freevmmap; + procstat_get_sem_info; procstat_get_shm_info; procstat_getargv; procstat_getauxv; diff --git a/lib/libprocstat/libprocstat.3 b/lib/libprocstat/libprocstat.3 index 3312427a0ed2..e82c30a21612 100644 --- a/lib/libprocstat/libprocstat.3 +++ b/lib/libprocstat/libprocstat.3 @@ -53,6 +53,7 @@ .Nm procstat_freevmmap , .Nm procstat_get_pipe_info , .Nm procstat_get_pts_info , +.Nm procstat_get_sem_info , .Nm procstat_get_shm_info , .Nm procstat_get_socket_info , .Nm procstat_get_vnode_info @@ -115,6 +116,13 @@ .Fa "char *errbuf" .Fc .Ft int +.Fo procstat_get_sem_info +.Fa "struct procstat *procstat" +.Fa "struct filestat *fst" +.Fa "struct semstat *sem" +.Fa "char *errbuf" +.Fc +.Ft int .Fo procstat_get_shm_info .Fa "struct procstat *procstat" .Fa "struct filestat *fst" @@ -463,12 +471,13 @@ function call. The .Fn procstat_get_pipe_info , .Fn procstat_get_pts_info , +.Fn procstat_get_sem_info , .Fn procstat_get_shm_info , .Fn procstat_get_socket_info and .Fn procstat_get_vnode_info functions are used to retrieve information about pipes, pseudo-terminals, -shared memory objects, +semaphores, shared memory objects, sockets, and vnodes, respectively. Each of them have a similar interface API. The @@ -505,6 +514,8 @@ argument indicates an actual error message in case of failure. .Nm procstat_get_pipe_info .It Li PS_FST_TYPE_PTS .Nm procstat_get_pts_info +.It Li PS_FST_TYPE_SEM +.Nm procstat_get_sem_info .It Li PS_FST_TYPE_SHM .Nm procstat_get_shm_info .El @@ -517,6 +528,7 @@ argument indicates an actual error message in case of failure. .Xr elf 3 , .Xr kvm 3 , .Xr queue 3 , +.Xr sem_open 3 , .Xr sysctl 3 , .Xr pts 4 , .Xr core 5 , diff --git a/lib/libprocstat/libprocstat.c b/lib/libprocstat/libprocstat.c index dd16c80d1c79..78eae9f7e4ed 100644 --- a/lib/libprocstat/libprocstat.c +++ b/lib/libprocstat/libprocstat.c @@ -59,6 +59,7 @@ __FBSDID("$FreeBSD$"); #define _WANT_FILE #include #include +#include #include #define _KERNEL #include @@ -129,6 +130,10 @@ static int procstat_get_pts_info_sysctl(struct filestat *fst, struct ptsstat *pts, char *errbuf); static int procstat_get_pts_info_kvm(kvm_t *kd, struct filestat *fst, struct ptsstat *pts, char *errbuf); +static int procstat_get_sem_info_sysctl(struct filestat *fst, + struct semstat *sem, char *errbuf); +static int procstat_get_sem_info_kvm(kvm_t *kd, struct filestat *fst, + struct semstat *sem, char *errbuf); static int procstat_get_shm_info_sysctl(struct filestat *fst, struct shmstat *shm, char *errbuf); static int procstat_get_shm_info_kvm(kvm_t *kd, struct filestat *fst, @@ -556,6 +561,10 @@ procstat_getfiles_kvm(struct procstat *procstat, struct kinfo_proc *kp, int mmap data = file.f_data; break; #endif + case DTYPE_SEM: + type = PS_FST_TYPE_SEM; + data = file.f_data; + break; case DTYPE_SHM: type = PS_FST_TYPE_SHM; data = file.f_data; @@ -1002,6 +1011,87 @@ procstat_get_pts_info_sysctl(struct filestat *fst, struct ptsstat *pts, return (0); } +int +procstat_get_sem_info(struct procstat *procstat, struct filestat *fst, + struct semstat *sem, char *errbuf) +{ + + assert(sem); + if (procstat->type == PROCSTAT_KVM) { + return (procstat_get_sem_info_kvm(procstat->kd, fst, sem, + errbuf)); + } else if (procstat->type == PROCSTAT_SYSCTL || + procstat->type == PROCSTAT_CORE) { + return (procstat_get_sem_info_sysctl(fst, sem, errbuf)); + } else { + warnx("unknown access method: %d", procstat->type); + snprintf(errbuf, _POSIX2_LINE_MAX, "error"); + return (1); + } +} + +static int +procstat_get_sem_info_kvm(kvm_t *kd, struct filestat *fst, + struct semstat *sem, char *errbuf) +{ + struct ksem ksem; + void *ksemp; + char *path; + int i; + + assert(kd); + assert(sem); + assert(fst); + bzero(sem, sizeof(*sem)); + ksemp = fst->fs_typedep; + if (ksemp == NULL) + goto fail; + if (!kvm_read_all(kd, (unsigned long)ksemp, &ksem, + sizeof(struct ksem))) { + warnx("can't read ksem at %p", (void *)ksemp); + goto fail; + } + sem->mode = S_IFREG | ksem.ks_mode; + sem->value = ksem.ks_value; + if (fst->fs_path == NULL && ksem.ks_path != NULL) { + path = malloc(MAXPATHLEN); + for (i = 0; i < MAXPATHLEN - 1; i++) { + if (!kvm_read_all(kd, (unsigned long)ksem.ks_path + i, + path + i, 1)) + break; + if (path[i] == '\0') + break; + } + path[i] = '\0'; + if (i == 0) + free(path); + else + fst->fs_path = path; + } + return (0); + +fail: + snprintf(errbuf, _POSIX2_LINE_MAX, "error"); + return (1); +} + +static int +procstat_get_sem_info_sysctl(struct filestat *fst, struct semstat *sem, + char *errbuf __unused) +{ + struct kinfo_file *kif; + + assert(sem); + assert(fst); + bzero(sem, sizeof(*sem)); + kif = fst->fs_typedep; + if (kif == NULL) + return (0); + sem->value = kif->kf_un.kf_sem.kf_sem_value; + sem->mode = kif->kf_un.kf_sem.kf_sem_mode; + return (0); +} + int procstat_get_shm_info(struct procstat *procstat, struct filestat *fst, struct shmstat *shm, char *errbuf) diff --git a/lib/libprocstat/libprocstat.h b/lib/libprocstat/libprocstat.h index 2c2662d5dbeb..65a5eb955324 100644 --- a/lib/libprocstat/libprocstat.h +++ b/lib/libprocstat/libprocstat.h @@ -133,6 +133,10 @@ struct pipestat { uint64_t addr; uint64_t peer; }; +struct semstat { + uint32_t value; + uint16_t mode; +}; struct shmstat { uint64_t size; uint16_t mode; @@ -177,6 +181,8 @@ int procstat_get_pipe_info(struct procstat *procstat, struct filestat *fst, struct pipestat *pipe, char *errbuf); int procstat_get_pts_info(struct procstat *procstat, struct filestat *fst, struct ptsstat *pts, char *errbuf); +int procstat_get_sem_info(struct procstat *procstat, struct filestat *fst, + struct semstat *sem, char *errbuf); int procstat_get_shm_info(struct procstat *procstat, struct filestat *fst, struct shmstat *shm, char *errbuf); int procstat_get_socket_info(struct procstat *procstat, struct filestat *fst, diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c index a9795ca74448..c0ecf1514cb6 100644 --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -55,6 +55,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -111,6 +112,7 @@ MALLOC_DECLARE(M_FADVISE); static uma_zone_t file_zone; +void (*ksem_info)(struct ksem *ks, char *path, size_t size, uint32_t *value); static int closefp(struct filedesc *fdp, int fd, struct file *fp, struct thread *td, int holdleaders); @@ -123,6 +125,7 @@ static int fill_pipe_info(struct pipe *pi, struct kinfo_file *kif); static int fill_procdesc_info(struct procdesc *pdp, struct kinfo_file *kif); static int fill_pts_info(struct tty *tp, struct kinfo_file *kif); +static int fill_sem_info(struct file *fp, struct kinfo_file *kif); static int fill_shm_info(struct file *fp, struct kinfo_file *kif); static int fill_socket_info(struct socket *so, struct kinfo_file *kif); static int fill_vnode_info(struct vnode *vp, struct kinfo_file *kif); @@ -2968,6 +2971,7 @@ sysctl_kern_proc_ofiledesc(SYSCTL_HANDLER_ARGS) struct shmfd *shmfd; struct socket *so; struct vnode *vp; + struct ksem *ks; struct file *fp; struct proc *p; struct tty *tp; @@ -2996,6 +3000,7 @@ sysctl_kern_proc_ofiledesc(SYSCTL_HANDLER_ARGS) continue; bzero(kif, sizeof(*kif)); kif->kf_structsize = sizeof(*kif); + ks = NULL; vp = NULL; so = NULL; tp = NULL; @@ -3041,6 +3046,7 @@ sysctl_kern_proc_ofiledesc(SYSCTL_HANDLER_ARGS) case DTYPE_SEM: kif->kf_type = KF_TYPE_SEM; + ks = fp->f_data; break; case DTYPE_PTS: @@ -3150,6 +3156,8 @@ sysctl_kern_proc_ofiledesc(SYSCTL_HANDLER_ARGS) } if (shmfd != NULL) shm_path(shmfd, kif->kf_path, sizeof(kif->kf_path)); + if (ks != NULL && ksem_info != NULL) + ksem_info(ks, kif->kf_path, sizeof(kif->kf_path), NULL); error = SYSCTL_OUT(req, kif, sizeof(*kif)); if (error) break; @@ -3220,6 +3228,9 @@ export_fd_to_sb(void *data, int type, int fd, int fflags, int refcnt, case KF_TYPE_PROCDESC: error = fill_procdesc_info((struct procdesc *)data, kif); break; + case KF_TYPE_SEM: + error = fill_sem_info((struct file *)data, kif); + break; case KF_TYPE_SHM: error = fill_shm_info((struct file *)data, kif); break; @@ -3387,6 +3398,7 @@ kern_proc_filedesc_out(struct proc *p, struct sbuf *sb, ssize_t maxlen) case DTYPE_SEM: type = KF_TYPE_SEM; + data = fp; break; case DTYPE_PTS: @@ -3620,6 +3632,25 @@ fill_procdesc_info(struct procdesc *pdp, struct kinfo_file *kif) return (0); } +static int +fill_sem_info(struct file *fp, struct kinfo_file *kif) +{ + struct thread *td; + struct stat sb; + + td = curthread; + if (fp->f_data == NULL) + return (1); + if (fo_stat(fp, &sb, td->td_ucred, td) != 0) + return (1); + if (ksem_info == NULL) + return (1); + ksem_info(fp->f_data, kif->kf_path, sizeof(kif->kf_path), + &kif->kf_un.kf_sem.kf_sem_value); + kif->kf_un.kf_sem.kf_sem_mode = sb.st_mode; + return (0); +} + static int fill_shm_info(struct file *fp, struct kinfo_file *kif) { diff --git a/sys/kern/uipc_sem.c b/sys/kern/uipc_sem.c index 509f32e909b7..a9f60f1e538d 100644 --- a/sys/kern/uipc_sem.c +++ b/sys/kern/uipc_sem.c @@ -71,7 +71,6 @@ FEATURE(p1003_1b_semaphores, "POSIX P1003.1B semaphores support"); * TODO * * - Resource limits? - * - Update fstat(1) * - Replace global sem_lock with mtx_pool locks? * - Add a MAC check_create() hook for creating new named semaphores. */ @@ -407,6 +406,7 @@ ksem_insert(char *path, Fnv32_t fnv, struct ksem *ks) map->km_path = path; map->km_fnv = fnv; map->km_ksem = ksem_hold(ks); + ks->ks_path = path; LIST_INSERT_HEAD(KSEM_HASH(fnv), map, km_link); } @@ -428,6 +428,7 @@ ksem_remove(char *path, Fnv32_t fnv, struct ucred *ucred) error = ksem_access(map->km_ksem, ucred); if (error) return (error); + map->km_ksem->ks_path = NULL; LIST_REMOVE(map, km_link); ksem_drop(map->km_ksem); free(map->km_path, M_KSEM); @@ -439,6 +440,20 @@ ksem_remove(char *path, Fnv32_t fnv, struct ucred *ucred) return (ENOENT); } +static void +ksem_info_impl(struct ksem *ks, char *path, size_t size, uint32_t *value) +{ + + if (ks->ks_path == NULL) + return; + sx_slock(&ksem_dict_lock); + if (ks->ks_path != NULL) + strlcpy(path, ks->ks_path, size); + if (value != NULL) + *value = ks->ks_value; + sx_sunlock(&ksem_dict_lock); +} + static int ksem_create_copyout_semid(struct thread *td, semid_t *semidp, int fd, int compat32) @@ -1014,6 +1029,7 @@ ksem_module_init(void) p31b_setcfg(CTL_P1003_1B_SEMAPHORES, 200112L); p31b_setcfg(CTL_P1003_1B_SEM_NSEMS_MAX, SEM_MAX); p31b_setcfg(CTL_P1003_1B_SEM_VALUE_MAX, SEM_VALUE_MAX); + ksem_info = ksem_info_impl; error = syscall_helper_register(ksem_syscalls); if (error) @@ -1035,6 +1051,7 @@ ksem_module_destroy(void) #endif syscall_helper_unregister(ksem_syscalls); + ksem_info = NULL; p31b_setcfg(CTL_P1003_1B_SEMAPHORES, 0); hashdestroy(ksem_dictionary, M_KSEM, ksem_hash); sx_destroy(&ksem_dict_lock); diff --git a/sys/sys/ksem.h b/sys/sys/ksem.h index da868fad1016..c11c8656b64d 100644 --- a/sys/sys/ksem.h +++ b/sys/sys/ksem.h @@ -29,7 +29,7 @@ #ifndef _POSIX4_KSEM_H_ #define _POSIX4_KSEM_H_ -#ifndef _KERNEL +#if !defined(_KERNEL) && !defined(_WANT_FILE) #error "no user-servicable parts inside" #endif @@ -57,9 +57,15 @@ struct ksem { struct timespec ks_birthtime; struct label *ks_label; /* MAC label */ + const char *ks_path; }; #define KS_ANONYMOUS 0x0001 /* Anonymous (unnamed) semaphore. */ #define KS_DEAD 0x0002 /* No new waiters allowed. */ +#ifdef _KERNEL +extern void (*ksem_info)(struct ksem *ks, char *path, size_t size, + uint32_t *value); +#endif + #endif /* !_POSIX4_KSEM_H_ */ diff --git a/sys/sys/user.h b/sys/sys/user.h index 2f6514bb25e6..aa81dc9c60ba 100644 --- a/sys/sys/user.h +++ b/sys/sys/user.h @@ -364,6 +364,10 @@ struct kinfo_file { uint16_t kf_file_pad0; uint32_t kf_file_pad1; } kf_file; + struct { + uint32_t kf_sem_value; + uint16_t kf_sem_mode; + } kf_sem; struct { uint64_t kf_pipe_addr; uint64_t kf_pipe_peer; diff --git a/usr.bin/fstat/fstat.1 b/usr.bin/fstat/fstat.1 index 7403a8e725ee..268b70f4526f 100644 --- a/usr.bin/fstat/fstat.1 +++ b/usr.bin/fstat/fstat.1 @@ -155,6 +155,8 @@ using a symbolic format (see otherwise, the mode is printed as an octal number. .It Li SZ\&|DV +If the file is a semaphore, +prints the current value of the semaphore. If the file is not a character or block special, prints the size of the file in bytes. Otherwise, if the diff --git a/usr.bin/fstat/fstat.c b/usr.bin/fstat/fstat.c index 265791d1daac..1aeee67511dd 100644 --- a/usr.bin/fstat/fstat.c +++ b/usr.bin/fstat/fstat.c @@ -84,6 +84,8 @@ static void print_pipe_info(struct procstat *procstat, struct filestat *fst); static void print_pts_info(struct procstat *procstat, struct filestat *fst); +static void print_sem_info(struct procstat *procstat, + struct filestat *fst); static void print_shm_info(struct procstat *procstat, struct filestat *fst); static void print_socket_info(struct procstat *procstat, @@ -294,6 +296,9 @@ print_file_info(struct procstat *procstat, struct filestat *fst, case PS_FST_TYPE_SHM: print_shm_info(procstat, fst); break; + case PS_FST_TYPE_SEM: + print_sem_info(procstat, fst); + break; default: if (vflg) fprintf(stderr, @@ -423,6 +428,30 @@ print_pts_info(struct procstat *procstat, struct filestat *fst) print_access_flags(fst->fs_fflags); } +static void +print_sem_info(struct procstat *procstat, struct filestat *fst) +{ + struct semstat sem; + char errbuf[_POSIX2_LINE_MAX]; + char mode[15]; + int error; + + error = procstat_get_sem_info(procstat, fst, &sem, errbuf); + if (error != 0) { + printf("* error"); + return; + } + if (nflg) { + printf(" "); + (void)snprintf(mode, sizeof(mode), "%o", sem.mode); + } else { + printf(" %-15s", fst->fs_path != NULL ? fst->fs_path : "-"); + strmode(sem.mode, mode); + } + printf(" %10s %6u", mode, sem.value); + print_access_flags(fst->fs_fflags); +} + static void print_shm_info(struct procstat *procstat, struct filestat *fst) { -- cgit v1.3 From f45590da3177703edc1ef5ababb3b980c52cc38c Mon Sep 17 00:00:00 2001 From: Sergey Kandaurov Date: Sat, 4 May 2013 12:44:00 +0000 Subject: Bump date. --- lib/libprocstat/libprocstat.3 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/libprocstat') diff --git a/lib/libprocstat/libprocstat.3 b/lib/libprocstat/libprocstat.3 index e82c30a21612..b472900dd8b9 100644 --- a/lib/libprocstat/libprocstat.3 +++ b/lib/libprocstat/libprocstat.3 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd April 20, 2013 +.Dd May 3, 2013 .Dt LIBPROCSTAT 3 .Os .Sh NAME -- cgit v1.3 From 467112b4d10e4aa4a63fd9ec81c2e155e0f68a7f Mon Sep 17 00:00:00 2001 From: Mikolaj Golub Date: Wed, 8 May 2013 19:11:47 +0000 Subject: Make errbuf optional, so if a caller is not interested in an error message she can pass NULL (procstat(1) already does this). MFC after: 2 weeks --- lib/libprocstat/libprocstat.c | 44 +++++++++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 14 deletions(-) (limited to 'lib/libprocstat') diff --git a/lib/libprocstat/libprocstat.c b/lib/libprocstat/libprocstat.c index 78eae9f7e4ed..cd38018559eb 100644 --- a/lib/libprocstat/libprocstat.c +++ b/lib/libprocstat/libprocstat.c @@ -897,7 +897,8 @@ procstat_get_pipe_info(struct procstat *procstat, struct filestat *fst, return (procstat_get_pipe_info_sysctl(fst, ps, errbuf)); } else { warnx("unknown access method: %d", procstat->type); - snprintf(errbuf, _POSIX2_LINE_MAX, "error"); + if (errbuf != NULL) + snprintf(errbuf, _POSIX2_LINE_MAX, "error"); return (1); } } @@ -926,7 +927,8 @@ procstat_get_pipe_info_kvm(kvm_t *kd, struct filestat *fst, return (0); fail: - snprintf(errbuf, _POSIX2_LINE_MAX, "error"); + if (errbuf != NULL) + snprintf(errbuf, _POSIX2_LINE_MAX, "error"); return (1); } @@ -962,7 +964,8 @@ procstat_get_pts_info(struct procstat *procstat, struct filestat *fst, return (procstat_get_pts_info_sysctl(fst, pts, errbuf)); } else { warnx("unknown access method: %d", procstat->type); - snprintf(errbuf, _POSIX2_LINE_MAX, "error"); + if (errbuf != NULL) + snprintf(errbuf, _POSIX2_LINE_MAX, "error"); return (1); } } @@ -990,7 +993,8 @@ procstat_get_pts_info_kvm(kvm_t *kd, struct filestat *fst, return (0); fail: - snprintf(errbuf, _POSIX2_LINE_MAX, "error"); + if (errbuf != NULL) + snprintf(errbuf, _POSIX2_LINE_MAX, "error"); return (1); } @@ -1025,7 +1029,8 @@ procstat_get_sem_info(struct procstat *procstat, struct filestat *fst, return (procstat_get_sem_info_sysctl(fst, sem, errbuf)); } else { warnx("unknown access method: %d", procstat->type); - snprintf(errbuf, _POSIX2_LINE_MAX, "error"); + if (errbuf != NULL) + snprintf(errbuf, _POSIX2_LINE_MAX, "error"); return (1); } } @@ -1071,7 +1076,8 @@ procstat_get_sem_info_kvm(kvm_t *kd, struct filestat *fst, return (0); fail: - snprintf(errbuf, _POSIX2_LINE_MAX, "error"); + if (errbuf != NULL) + snprintf(errbuf, _POSIX2_LINE_MAX, "error"); return (1); } @@ -1106,7 +1112,8 @@ procstat_get_shm_info(struct procstat *procstat, struct filestat *fst, return (procstat_get_shm_info_sysctl(fst, shm, errbuf)); } else { warnx("unknown access method: %d", procstat->type); - snprintf(errbuf, _POSIX2_LINE_MAX, "error"); + if (errbuf != NULL) + snprintf(errbuf, _POSIX2_LINE_MAX, "error"); return (1); } } @@ -1152,7 +1159,8 @@ procstat_get_shm_info_kvm(kvm_t *kd, struct filestat *fst, return (0); fail: - snprintf(errbuf, _POSIX2_LINE_MAX, "error"); + if (errbuf != NULL) + snprintf(errbuf, _POSIX2_LINE_MAX, "error"); return (1); } @@ -1187,7 +1195,8 @@ procstat_get_vnode_info(struct procstat *procstat, struct filestat *fst, return (procstat_get_vnode_info_sysctl(fst, vn, errbuf)); } else { warnx("unknown access method: %d", procstat->type); - snprintf(errbuf, _POSIX2_LINE_MAX, "error"); + if (errbuf != NULL) + snprintf(errbuf, _POSIX2_LINE_MAX, "error"); return (1); } } @@ -1254,7 +1263,8 @@ procstat_get_vnode_info_kvm(kvm_t *kd, struct filestat *fst, break; } if (i == NTYPES) { - snprintf(errbuf, _POSIX2_LINE_MAX, "?(%s)", tagstr); + if (errbuf != NULL) + snprintf(errbuf, _POSIX2_LINE_MAX, "?(%s)", tagstr); return (1); } vn->vn_mntdir = getmnton(kd, vnode.v_mount); @@ -1268,7 +1278,8 @@ procstat_get_vnode_info_kvm(kvm_t *kd, struct filestat *fst, return (0); fail: - snprintf(errbuf, _POSIX2_LINE_MAX, "error"); + if (errbuf != NULL) + snprintf(errbuf, _POSIX2_LINE_MAX, "error"); return (1); } @@ -1349,7 +1360,10 @@ procstat_get_vnode_info_sysctl(struct filestat *fst, struct vnstat *vn, if (vntype == PS_FST_VTYPE_VNON || vntype == PS_FST_VTYPE_VBAD) return (0); if ((status & KF_ATTR_VALID) == 0) { - snprintf(errbuf, _POSIX2_LINE_MAX, "? (no info available)"); + if (errbuf != NULL) { + snprintf(errbuf, _POSIX2_LINE_MAX, + "? (no info available)"); + } return (1); } if (path && *path) { @@ -1390,7 +1404,8 @@ procstat_get_socket_info(struct procstat *procstat, struct filestat *fst, return (procstat_get_socket_info_sysctl(fst, sock, errbuf)); } else { warnx("unknown access method: %d", procstat->type); - snprintf(errbuf, _POSIX2_LINE_MAX, "error"); + if (errbuf != NULL) + snprintf(errbuf, _POSIX2_LINE_MAX, "error"); return (1); } } @@ -1488,7 +1503,8 @@ procstat_get_socket_info_kvm(kvm_t *kd, struct filestat *fst, return (0); fail: - snprintf(errbuf, _POSIX2_LINE_MAX, "error"); + if (errbuf != NULL) + snprintf(errbuf, _POSIX2_LINE_MAX, "error"); return (1); } -- cgit v1.3 From 608203fd94e4558b9dd9073545871adeabd63650 Mon Sep 17 00:00:00 2001 From: John Baldwin Date: Tue, 11 Jun 2013 20:00:49 +0000 Subject: Borrow the algorithm from kvm_getprocs() to fix procstat_getprocs() to handle the case where the process tables grows in between the calls to fetch the size and fetch the table. MFC after: 1 week --- lib/libprocstat/libprocstat.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'lib/libprocstat') diff --git a/lib/libprocstat/libprocstat.c b/lib/libprocstat/libprocstat.c index cd38018559eb..7626c19e1019 100644 --- a/lib/libprocstat/libprocstat.c +++ b/lib/libprocstat/libprocstat.c @@ -253,7 +253,7 @@ procstat_getprocs(struct procstat *procstat, int what, int arg, unsigned int *count) { struct kinfo_proc *p0, *p; - size_t len; + size_t len, olen; int name[4]; int cnt; int error; @@ -290,12 +290,16 @@ procstat_getprocs(struct procstat *procstat, int what, int arg, warnx("no processes?"); goto fail; } - p = malloc(len); - if (p == NULL) { - warnx("malloc(%zu)", len); - goto fail; - } - error = sysctl(name, 4, p, &len, NULL, 0); + do { + len += len / 10; + p = reallocf(p, len); + if (p == NULL) { + warnx("reallocf(%zu)", len); + goto fail; + } + olen = len; + error = sysctl(name, 4, p, &len, NULL, 0); + } while (error < 0 && errno == ENOMEM && olen == len); if (error < 0 && errno != EPERM) { warn("sysctl(kern.proc)"); goto fail; -- cgit v1.3 From 237abf0c56afd2f4846230b70b42b4c3d02d2d19 Mon Sep 17 00:00:00 2001 From: Davide Italiano Date: Fri, 28 Jun 2013 21:00:08 +0000 Subject: - Trim an unused and bogus Makefile for mount_smbfs. - Reconnect with some minor modifications, in particular now selsocket() internals are adapted to use sbintime units after recent'ish calloutng switch. --- contrib/smbfs/mount_smbfs/Makefile | 18 ------------- etc/defaults/rc.conf | 2 +- etc/mtree/BSD.include.dist | 2 ++ etc/mtree/BSD.usr.dist | 4 +++ include/Makefile | 5 ++-- lib/Makefile | 8 ++++++ lib/libprocstat/Makefile | 1 + lib/libprocstat/common_kvm.h | 1 + lib/libprocstat/libprocstat.c | 1 + rescue/rescue/Makefile | 2 ++ sbin/mount/mount.8 | 2 ++ sbin/mount/mount.c | 2 +- share/examples/Makefile | 1 + share/examples/etc/README.examples | 1 + share/mk/bsd.libnames.mk | 1 + sys/conf/NOTES | 7 +++++ sys/conf/files | 20 ++++++++++++-- sys/conf/files.amd64 | 2 +- sys/conf/files.arm | 2 +- sys/conf/files.i386 | 2 +- sys/conf/files.ia64 | 2 +- sys/conf/files.mips | 2 +- sys/conf/files.pc98 | 2 +- sys/conf/files.powerpc | 2 +- sys/conf/files.sparc64 | 2 +- sys/conf/options | 4 +++ sys/kern/Make.tags.inc | 1 + sys/kern/sys_generic.c | 55 ++++++++++++++++++++++++++++++++++++++ sys/modules/Makefile | 6 +++++ sys/sys/socketvar.h | 2 ++ usr.bin/Makefile.amd64 | 1 + usr.bin/Makefile.i386 | 1 + usr.bin/Makefile.ia64 | 1 + usr.bin/Makefile.powerpc | 1 + usr.bin/Makefile.sparc64 | 1 + usr.bin/kdump/kdump.c | 2 ++ usr.sbin/Makefile.amd64 | 1 + usr.sbin/Makefile.i386 | 1 + usr.sbin/Makefile.ia64 | 1 + usr.sbin/Makefile.powerpc | 1 + usr.sbin/Makefile.sparc64 | 1 + 41 files changed, 142 insertions(+), 32 deletions(-) delete mode 100644 contrib/smbfs/mount_smbfs/Makefile (limited to 'lib/libprocstat') diff --git a/contrib/smbfs/mount_smbfs/Makefile b/contrib/smbfs/mount_smbfs/Makefile deleted file mode 100644 index ffd79c9d4a56..000000000000 --- a/contrib/smbfs/mount_smbfs/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -# $Id: Makefile,v 1.7 2001/04/16 04:34:26 bp Exp $ - -PROG= mount_smbfs -SRCS= mount_smbfs.c getmntopts.c -MAN8= mount_smbfs.8 - -BINDIR= /sbin -#NOSHARED=yes - -MOUNT= ${.CURDIR}/../mount -CFLAGS+= -DSMBFS -I${MOUNT} - -.PATH: ${MOUNT} - -LDADD+= -lsmb -DPADD+= ${LIBSMB} - -.include diff --git a/etc/defaults/rc.conf b/etc/defaults/rc.conf index dda185505de5..47d51455bd8f 100644 --- a/etc/defaults/rc.conf +++ b/etc/defaults/rc.conf @@ -88,7 +88,7 @@ fsck_y_enable="NO" # Set to YES to do fsck -y if the initial preen fails. fsck_y_flags="" # Additional flags for fsck -y background_fsck="YES" # Attempt to run fsck in the background where possible. background_fsck_delay="60" # Time to wait (seconds) before starting the fsck. -netfs_types="nfs:NFS oldnfs:OLDNFS" # Net filesystems. +netfs_types="nfs:NFS oldnfs:OLDNFS smbfs:SMB" # Net filesystems. extra_netfs_types="NO" # List of network extra filesystem types for delayed # mount at startup (or NO). diff --git a/etc/mtree/BSD.include.dist b/etc/mtree/BSD.include.dist index 02e831d7d511..e29534841b0d 100644 --- a/etc/mtree/BSD.include.dist +++ b/etc/mtree/BSD.include.dist @@ -176,6 +176,8 @@ .. procfs .. + smbfs + .. udf .. unionfs diff --git a/etc/mtree/BSD.usr.dist b/etc/mtree/BSD.usr.dist index 02d2286e5375..98e89b90bcf4 100644 --- a/etc/mtree/BSD.usr.dist +++ b/etc/mtree/BSD.usr.dist @@ -309,6 +309,10 @@ srcs .. .. + smbfs + print + .. + .. sunrpc dir .. diff --git a/include/Makefile b/include/Makefile index 4ccb759d57ac..ae5ed7ce7737 100644 --- a/include/Makefile +++ b/include/Makefile @@ -37,7 +37,7 @@ LHDRS= aio.h errno.h fcntl.h linker_set.h poll.h stdatomic.h stdint.h \ syslog.h ucontext.h LDIRS= bsm cam geom net net80211 netatalk netgraph netinet netinet6 \ - netipsec ${_netipx} netnatm \ + netipsec ${_netipx} netnatm netsmb \ nfs nfsclient nfsserver \ sys vm @@ -48,7 +48,7 @@ LSUBDIRS= cam/ata cam/scsi \ dev/ofw dev/pbio dev/pci ${_dev_powermac_nvram} dev/ppbus dev/smbus \ dev/speaker dev/usb dev/utopia dev/vkbd dev/wi \ fs/devfs fs/fdescfs fs/msdosfs fs/nandfs fs/nfs fs/nullfs \ - fs/procfs fs/udf fs/unionfs \ + fs/procfs fs/smbfs fs/udf fs/unionfs \ geom/cache geom/concat geom/eli geom/gate geom/journal geom/label \ geom/mirror geom/mountver geom/multipath geom/nop \ geom/raid geom/raid3 geom/shsec geom/stripe geom/virstor \ @@ -80,6 +80,7 @@ INCS+= iconv.h LSUBSUBDIRS+= netgraph/bluetooth/include .endif +# XXX unconditionally needed by #.if ${MK_IPX} != "no" _netipx= netipx #.endif diff --git a/lib/Makefile b/lib/Makefile index d28d55bc4422..71fe4d2354e4 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -102,6 +102,7 @@ SUBDIR= ${SUBDIR_ORDERED} \ ${_librtld_db} \ ${_libsdp} \ ${_libsm} \ + ${_libsmb} \ ${_libsmdb} \ ${_libsmutil} \ libstand \ @@ -205,6 +206,7 @@ _libypclnt= libypclnt .endif .if ${MACHINE_CPUARCH} == "i386" || ${MACHINE_CPUARCH} == "amd64" +_libsmb= libsmb _libvgl= libvgl _libproc= libproc _librtld_db= librtld_db @@ -216,6 +218,7 @@ _libvmmapi= libvmmapi .if ${MACHINE_CPUARCH} == "ia64" _libefi= libefi +_libsmb= libsmb .endif .if ${MACHINE_CPUARCH} == "mips" @@ -226,6 +229,11 @@ _librtld_db= librtld_db .if ${MACHINE_CPUARCH} == "powerpc" _libproc= libproc _librtld_db= librtld_db +_libsmb= libsmb +.endif + +.if ${MACHINE_CPUARCH} == "sparc64" +_libsmb= libsmb .endif .if ${MK_OPENSSL} != "no" diff --git a/lib/libprocstat/Makefile b/lib/libprocstat/Makefile index 1ba2398ace5b..af5a775d7d05 100644 --- a/lib/libprocstat/Makefile +++ b/lib/libprocstat/Makefile @@ -9,6 +9,7 @@ SRCS= cd9660.c \ core.c \ libprocstat.c \ msdosfs.c \ + smbfs.c \ udf.c VERSION_DEF= ${.CURDIR}/Versions.def diff --git a/lib/libprocstat/common_kvm.h b/lib/libprocstat/common_kvm.h index d5e08e1cfc09..06627bff448c 100644 --- a/lib/libprocstat/common_kvm.h +++ b/lib/libprocstat/common_kvm.h @@ -41,6 +41,7 @@ int devfs_filestat(kvm_t *kd, struct vnode *vp, struct vnstat *vn); int isofs_filestat(kvm_t *kd, struct vnode *vp, struct vnstat *vn); int msdosfs_filestat(kvm_t *kd, struct vnode *vp, struct vnstat *vn); int nfs_filestat(kvm_t *kd, struct vnode *vp, struct vnstat *vn); +int smbfs_filestat(kvm_t *kd, struct vnode *vp, struct vnstat *vn); int udf_filestat(kvm_t *kd, struct vnode *vp, struct vnstat *vn); int ufs_filestat(kvm_t *kd, struct vnode *vp, struct vnstat *vn); int zfs_filestat(kvm_t *kd, struct vnode *vp, struct vnstat *vn); diff --git a/lib/libprocstat/libprocstat.c b/lib/libprocstat/libprocstat.c index 7626c19e1019..dfb5ed328194 100644 --- a/lib/libprocstat/libprocstat.c +++ b/lib/libprocstat/libprocstat.c @@ -1220,6 +1220,7 @@ procstat_get_vnode_info_kvm(kvm_t *kd, struct filestat *fst, FSTYPE(isofs), FSTYPE(msdosfs), FSTYPE(nfs), + FSTYPE(smbfs), FSTYPE(udf), FSTYPE(ufs), #ifdef LIBPROCSTAT_ZFS diff --git a/rescue/rescue/Makefile b/rescue/rescue/Makefile index caec928fee7e..80acf63bf0f0 100644 --- a/rescue/rescue/Makefile +++ b/rescue/rescue/Makefile @@ -130,6 +130,8 @@ CRUNCH_LIBS+= -lgeom -lbsdxml -lkiconv -lmd -lsbuf -lufs -lz .if ${MACHINE_CPUARCH} == "i386" CRUNCH_PROGS_sbin+= bsdlabel sconfig fdisk CRUNCH_ALIAS_bsdlabel= disklabel +#CRUNCH_PROGS+= mount_smbfs +#CRUNCH_LIBS+= -lsmb .endif .if ${MACHINE} == "pc98" diff --git a/sbin/mount/mount.8 b/sbin/mount/mount.8 index 7cd80266ac51..5b670eeaf5f1 100644 --- a/sbin/mount/mount.8 +++ b/sbin/mount/mount.8 @@ -450,6 +450,7 @@ However, for the following file system types: .Cm nfs , .Cm nullfs , .Cm oldnfs , +.Cm smbfs , .Cm udf , and .Cm unionfs . @@ -544,6 +545,7 @@ support for a particular file system might be provided either on a static .Xr mount_msdosfs 8 , .Xr mount_nfs 8 , .Xr mount_nullfs 8 , +.Xr mount_smbfs 8 , .Xr mount_udf 8 , .Xr mount_unionfs 8 , .Xr umount 8 , diff --git a/sbin/mount/mount.c b/sbin/mount/mount.c index a156089dc99b..6284822239e3 100644 --- a/sbin/mount/mount.c +++ b/sbin/mount/mount.c @@ -143,7 +143,7 @@ use_mountprog(const char *vfstype) unsigned int i; const char *fs[] = { "cd9660", "mfs", "msdosfs", "nfs", - "nullfs", "oldnfs", "udf", "unionfs", + "nullfs", "oldnfs", "smbfs", "udf", "unionfs", NULL }; diff --git a/share/examples/Makefile b/share/examples/Makefile index 90bef45f6dfc..04f53d683a2c 100644 --- a/share/examples/Makefile +++ b/share/examples/Makefile @@ -240,6 +240,7 @@ etc-examples: .endif .if ${SHARED} != "symlinks" +SUBDIR= smbfs .if ${MK_ATF} != "no" SUBDIR+=atf .endif diff --git a/share/examples/etc/README.examples b/share/examples/etc/README.examples index d703edbf5681..f7bf4ceb8cfb 100644 --- a/share/examples/etc/README.examples +++ b/share/examples/etc/README.examples @@ -40,6 +40,7 @@ netstart - network startup script run from /etc/rc network.subr - routines for network configuration scripts networks - see networks(5) newsyslog.conf - configuration for system log file rotator newsyslog(8) +nsmb.conf - smbfs lookups configuration file opieaccess - OPIE database of trusted networks pf.conf - pf(4) example configuration file pf.os - SYN fingerprint database diff --git a/share/mk/bsd.libnames.mk b/share/mk/bsd.libnames.mk index e11ac8163b12..f78a6564840d 100644 --- a/share/mk/bsd.libnames.mk +++ b/share/mk/bsd.libnames.mk @@ -149,6 +149,7 @@ LIBRT?= ${DESTDIR}${LIBDIR}/librt.a LIBRTLD_DB?= ${DESTDIR}${LIBDIR}/librtld_db.a LIBSBUF?= ${DESTDIR}${LIBDIR}/libsbuf.a LIBSDP?= ${DESTDIR}${LIBDIR}/libsdp.a +LIBSMB?= ${DESTDIR}${LIBDIR}/libsmb.a LIBSSH?= ${DESTDIR}${LIBDIR}/libssh.a LIBSSL?= ${DESTDIR}${LIBDIR}/libssl.a LIBSTAND?= ${DESTDIR}${LIBDIR}/libstand.a diff --git a/sys/conf/NOTES b/sys/conf/NOTES index 3961e0f13893..dce216800a32 100644 --- a/sys/conf/NOTES +++ b/sys/conf/NOTES @@ -602,6 +602,12 @@ options IPX #IPX/SPX communications protocols options NETATALK #Appletalk communications protocols options NETATALKDEBUG #Appletalk debugging +# +# SMB/CIFS requester +# NETSMB enables support for SMB protocol, it requires LIBMCHAIN and LIBICONV +# options. +options NETSMB #SMB/CIFS requester + # mchain library. It can be either loaded as KLD or compiled into kernel options LIBMCHAIN @@ -1038,6 +1044,7 @@ options NULLFS #NULL filesystem options PROCFS #Process filesystem (requires PSEUDOFS) options PSEUDOFS #Pseudo-filesystem framework options PSEUDOFS_TRACE #Debugging support for PSEUDOFS +options SMBFS #SMB/CIFS filesystem options TMPFS #Efficient memory filesystem options UDF #Universal Disk Format options UNIONFS #Union filesystem diff --git a/sys/conf/files b/sys/conf/files index 4dc89148f04e..385a4eb1c666 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -536,8 +536,8 @@ crypto/blowfish/bf_ecb.c optional ipsec crypto/blowfish/bf_skey.c optional crypto | ipsec crypto/camellia/camellia.c optional crypto | ipsec crypto/camellia/camellia-api.c optional crypto | ipsec -crypto/des/des_ecb.c optional crypto | ipsec -crypto/des/des_setkey.c optional crypto | ipsec +crypto/des/des_ecb.c optional crypto | ipsec | netsmb +crypto/des/des_setkey.c optional crypto | ipsec | netsmb crypto/rc4/rc4.c optional netgraph_mppc_encryption | kgssapi crypto/rijndael/rijndael-alg-fst.c optional crypto | geom_bde | \ ipsec | random | wlan_ccmp @@ -2509,6 +2509,12 @@ fs/pseudofs/pseudofs.c optional pseudofs fs/pseudofs/pseudofs_fileno.c optional pseudofs fs/pseudofs/pseudofs_vncache.c optional pseudofs fs/pseudofs/pseudofs_vnops.c optional pseudofs +fs/smbfs/smbfs_io.c optional smbfs +fs/smbfs/smbfs_node.c optional smbfs +fs/smbfs/smbfs_smb.c optional smbfs +fs/smbfs/smbfs_subr.c optional smbfs +fs/smbfs/smbfs_vfsops.c optional smbfs +fs/smbfs/smbfs_vnops.c optional smbfs fs/udf/osta.c optional udf fs/udf/udf_iconv.c optional udf_iconv fs/udf/udf_vfsops.c optional udf @@ -2746,6 +2752,7 @@ kern/kern_uuid.c standard kern/kern_xxx.c standard kern/link_elf.c standard kern/linker_if.m standard +kern/md4c.c optional netsmb kern/md5c.c standard kern/p1003_1b.c standard kern/posix4_mib.c standard @@ -3279,6 +3286,15 @@ netpfil/pf/pf_osfp.c optional pf inet netpfil/pf/pf_ruleset.c optional pf inet netpfil/pf/pf_table.c optional pf inet netpfil/pf/in4_cksum.c optional pf inet +netsmb/smb_conn.c optional netsmb +netsmb/smb_crypt.c optional netsmb +netsmb/smb_dev.c optional netsmb +netsmb/smb_iod.c optional netsmb +netsmb/smb_rq.c optional netsmb +netsmb/smb_smb.c optional netsmb +netsmb/smb_subr.c optional netsmb +netsmb/smb_trantcp.c optional netsmb +netsmb/smb_usr.c optional netsmb nfs/bootp_subr.c optional bootp nfsclient | bootp nfscl nfs/krpc_subr.c optional bootp nfsclient | bootp nfscl nfs/nfs_common.c optional nfsclient | nfsserver diff --git a/sys/conf/files.amd64 b/sys/conf/files.amd64 index 7a41a269c8f1..2cb1981cf3f3 100644 --- a/sys/conf/files.amd64 +++ b/sys/conf/files.amd64 @@ -136,7 +136,7 @@ crypto/aesni/aeskeys_amd64.S optional aesni crypto/aesni/aesni.c optional aesni crypto/aesni/aesni_wrap.c optional aesni crypto/blowfish/bf_enc.c optional crypto | ipsec -crypto/des/des_enc.c optional crypto | ipsec +crypto/des/des_enc.c optional crypto | ipsec | netsmb crypto/via/padlock.c optional padlock crypto/via/padlock_cipher.c optional padlock crypto/via/padlock_hash.c optional padlock diff --git a/sys/conf/files.arm b/sys/conf/files.arm index 938386d70bff..ac487041f6f4 100644 --- a/sys/conf/files.arm +++ b/sys/conf/files.arm @@ -61,7 +61,7 @@ board_id.h standard \ clean "board_id.h" cddl/compat/opensolaris/kern/opensolaris_atomic.c optional zfs compile-with "${ZFS_C}" crypto/blowfish/bf_enc.c optional crypto | ipsec -crypto/des/des_enc.c optional crypto | ipsec +crypto/des/des_enc.c optional crypto | ipsec | netsmb dev/fb/fb.c optional sc dev/hwpmc/hwpmc_arm.c optional hwpmc dev/kbd/kbd.c optional sc diff --git a/sys/conf/files.i386 b/sys/conf/files.i386 index 218472b71c52..0f65d3b8a3dd 100644 --- a/sys/conf/files.i386 +++ b/sys/conf/files.i386 @@ -122,7 +122,7 @@ crypto/aesni/aesencdec_i386.S optional aesni crypto/aesni/aeskeys_i386.S optional aesni crypto/aesni/aesni.c optional aesni crypto/aesni/aesni_wrap.c optional aesni -crypto/des/arch/i386/des_enc.S optional crypto | ipsec +crypto/des/arch/i386/des_enc.S optional crypto | ipsec | netsmb crypto/via/padlock.c optional padlock crypto/via/padlock_cipher.c optional padlock crypto/via/padlock_hash.c optional padlock diff --git a/sys/conf/files.ia64 b/sys/conf/files.ia64 index 474ba1b8132e..6719c9870658 100644 --- a/sys/conf/files.ia64 +++ b/sys/conf/files.ia64 @@ -41,7 +41,7 @@ contrib/ia64/libuwx/src/uwx_trace.c standard contrib/ia64/libuwx/src/uwx_uinfo.c standard contrib/ia64/libuwx/src/uwx_utable.c standard crypto/blowfish/bf_enc.c optional crypto | ipsec -crypto/des/des_enc.c optional crypto | ipsec +crypto/des/des_enc.c optional crypto | ipsec | netsmb dev/atkbdc/atkbd.c optional atkbd atkbdc dev/atkbdc/atkbd_atkbdc.c optional atkbd atkbdc dev/atkbdc/atkbdc.c optional atkbdc diff --git a/sys/conf/files.mips b/sys/conf/files.mips index 79676b992887..ca8dee27a415 100644 --- a/sys/conf/files.mips +++ b/sys/conf/files.mips @@ -77,7 +77,7 @@ dev/uart/uart_cpu_fdt.c optional uart fdt # crypto support -- use generic crypto/blowfish/bf_enc.c optional crypto | ipsec -crypto/des/des_enc.c optional crypto | ipsec +crypto/des/des_enc.c optional crypto | ipsec | netsmb # AP common nvram interface MIPS specific, but maybe should be more generic dev/nvram2env/nvram2env.c optional nvram2env diff --git a/sys/conf/files.pc98 b/sys/conf/files.pc98 index 252ecdddeac9..a8e60b6f7290 100644 --- a/sys/conf/files.pc98 +++ b/sys/conf/files.pc98 @@ -77,7 +77,7 @@ bf_enc.o optional crypto | ipsec \ dependency "$S/crypto/blowfish/arch/i386/bf_enc.S $S/crypto/blowfish/arch/i386/bf_enc_586.S $S/crypto/blowfish/arch/i386/bf_enc_686.S" \ compile-with "${CC} -c -I$S/crypto/blowfish/arch/i386 ${ASM_CFLAGS} ${WERROR} ${.IMPSRC}" \ no-implicit-rule -crypto/des/arch/i386/des_enc.S optional crypto | ipsec +crypto/des/arch/i386/des_enc.S optional crypto | ipsec | netsmb dev/agp/agp_ali.c optional agp dev/agp/agp_amd.c optional agp dev/agp/agp_i810.c optional agp diff --git a/sys/conf/files.powerpc b/sys/conf/files.powerpc index 96331f7ad0aa..5808d856838f 100644 --- a/sys/conf/files.powerpc +++ b/sys/conf/files.powerpc @@ -18,7 +18,7 @@ font.h optional sc \ cddl/compat/opensolaris/kern/opensolaris_atomic.c optional zfs powerpc compile-with "${ZFS_C}" cddl/contrib/opensolaris/common/atomic/powerpc64/opensolaris_atomic.S optional zfs powerpc64 compile-with "${ZFS_S}" crypto/blowfish/bf_enc.c optional crypto | ipsec -crypto/des/des_enc.c optional crypto | ipsec +crypto/des/des_enc.c optional crypto | ipsec | netsmb dev/bm/if_bm.c optional bm powermac dev/adb/adb_bus.c optional adb dev/adb/adb_kbd.c optional adb diff --git a/sys/conf/files.sparc64 b/sys/conf/files.sparc64 index 5019dabeab86..a0fad9b5477d 100644 --- a/sys/conf/files.sparc64 +++ b/sys/conf/files.sparc64 @@ -24,7 +24,7 @@ ukbdmap.h optional ukbd_dflt_keymap \ # cddl/contrib/opensolaris/common/atomic/sparc64/opensolaris_atomic.S optional zfs compile-with "${ZFS_S}" crypto/blowfish/bf_enc.c optional crypto | ipsec -crypto/des/des_enc.c optional crypto | ipsec +crypto/des/des_enc.c optional crypto | ipsec | netsmb dev/atkbdc/atkbd.c optional atkbd atkbdc dev/atkbdc/atkbd_atkbdc.c optional atkbd atkbdc dev/atkbdc/atkbdc.c optional atkbdc diff --git a/sys/conf/options b/sys/conf/options index 03936fd94b40..752893d32e6f 100644 --- a/sys/conf/options +++ b/sys/conf/options @@ -222,6 +222,7 @@ NULLFS opt_dontuse.h PROCFS opt_dontuse.h PSEUDOFS opt_dontuse.h REISERFS opt_dontuse.h +SMBFS opt_dontuse.h TMPFS opt_dontuse.h UDF opt_dontuse.h UNIONFS opt_dontuse.h @@ -287,6 +288,9 @@ UFS_GJOURNAL opt_ufs.h # they won't make any difference yet). NFS_ROOT opt_nfsroot.h +# SMB/CIFS requester +NETSMB opt_netsmb.h + # Options used only in subr_param.c. HZ opt_param.h MAXFILES opt_param.h diff --git a/sys/kern/Make.tags.inc b/sys/kern/Make.tags.inc index 81205a6b429b..cb8a3ff993e7 100644 --- a/sys/kern/Make.tags.inc +++ b/sys/kern/Make.tags.inc @@ -30,6 +30,7 @@ COMM= ${SYS}/dev/advansys/*.[ch] \ ${SYS}/fs/msdosfs/*.[ch] \ ${SYS}/fs/nullfs/*.[ch] \ ${SYS}/fs/procfs/*.[ch] \ + ${SYS}/fs/smbfs/*.[ch] \ ${SYS}/fs/udf/*.[ch] \ ${SYS}/fs/unionfs/*.[ch] \ ${SYS}/geom/*.[ch] \ diff --git a/sys/kern/sys_generic.c b/sys/kern/sys_generic.c index 45b9327683dd..a12773be5316 100644 --- a/sys/kern/sys_generic.c +++ b/sys/kern/sys_generic.c @@ -1497,6 +1497,61 @@ sys_openbsd_poll(td, uap) return (sys_poll(td, (struct poll_args *)uap)); } +/* + * XXX This was created specifically to support netncp and netsmb. This + * allows the caller to specify a socket to wait for events on. It returns + * 0 if any events matched and an error otherwise. There is no way to + * determine which events fired. + */ +int +selsocket(struct socket *so, int events, struct timeval *tvp, struct thread *td) +{ + struct timeval rtv; + sbintime_t asbt, precision, rsbt; + int error; + + if (tvp != NULL) { + rtv = *tvp; + if (rtv.tv_sec < 0 || rtv.tv_usec < 0 || + rtv.tv_usec >= 1000000) + return (EINVAL); + if (!timevalisset(&rtv)) + asbt = 0; + else if (rtv.tv_sec <= INT32_MAX) { + rsbt = tvtosbt(rtv); + precision = rsbt; + precision >>= tc_precexp; + if (TIMESEL(&asbt, rsbt)) + asbt += tc_tick_sbt; + if (asbt <= INT64_MAX - rsbt) + asbt += rsbt; + else + asbt = -1; + } else + asbt = -1; + } else + asbt = -1; + seltdinit(td); + /* + * Iterate until the timeout expires or the socket becomes ready. + */ + for (;;) { + selfdalloc(td, NULL); + error = sopoll(so, events, NULL, td); + /* error here is actually the ready events. */ + if (error) + return (0); + error = seltdwait(td, asbt, precision); + if (error) + break; + } + seltdclear(td); + /* XXX Duplicates ncp/smb behavior. */ + if (error == ERESTART) + error = 0; + return (error); +} + /* * Preallocate two selfds associated with 'cookie'. Some fo_poll routines * have two select sets, one for read and another for write. diff --git a/sys/modules/Makefile b/sys/modules/Makefile index 75cc5bd5bf57..e43d561cf1c1 100644 --- a/sys/modules/Makefile +++ b/sys/modules/Makefile @@ -301,6 +301,7 @@ SUBDIR= \ siis \ sis \ sk \ + ${_smbfs} \ ${_sn} \ ${_snc} \ snp \ @@ -520,6 +521,7 @@ _rdma= rdma _safe= safe _sbni= sbni _scsi_low= scsi_low +_smbfs= smbfs _sound= sound _speaker= speaker _splash= splash @@ -722,6 +724,7 @@ _s3= s3 _safe= safe _scsi_low= scsi_low _sfxge= sfxge +_smbfs= smbfs _sound= sound _speaker= speaker _splash= splash @@ -779,6 +782,7 @@ _ips= ips _mly= mly _pccard= pccard _scsi_low= scsi_low +_smbfs= smbfs _sound= sound _splash= splash _sppp= sppp @@ -801,6 +805,7 @@ _drm= drm _exca= exca _nvram= powermac_nvram _pccard= pccard +_smbfs= smbfs _sound= sound _cyclic= cyclic _dtrace= dtrace @@ -827,6 +832,7 @@ _igb= igb .if ${MK_CDDL} != "no" || defined(ALL_MODULES) _opensolaris= opensolaris .endif +_smbfs= smbfs _sound= sound .if ${MK_ZFS} != "no" || defined(ALL_MODULES) _zfs= zfs diff --git a/sys/sys/socketvar.h b/sys/sys/socketvar.h index 77f31df336a7..89dec187cc91 100644 --- a/sys/sys/socketvar.h +++ b/sys/sys/socketvar.h @@ -371,6 +371,8 @@ void soupcall_clear(struct socket *so, int which); void soupcall_set(struct socket *so, int which, int (*func)(struct socket *, void *, int), void *arg); void sowakeup(struct socket *so, struct sockbuf *sb); +int selsocket(struct socket *so, int events, struct timeval *tv, + struct thread *td); /* * Accept filter functions (duh). diff --git a/usr.bin/Makefile.amd64 b/usr.bin/Makefile.amd64 index b720e3de68bf..fee2fb076811 100644 --- a/usr.bin/Makefile.amd64 +++ b/usr.bin/Makefile.amd64 @@ -1,2 +1,3 @@ # $FreeBSD$ +SUBDIR+= smbutil diff --git a/usr.bin/Makefile.i386 b/usr.bin/Makefile.i386 index b720e3de68bf..fee2fb076811 100644 --- a/usr.bin/Makefile.i386 +++ b/usr.bin/Makefile.i386 @@ -1,2 +1,3 @@ # $FreeBSD$ +SUBDIR+= smbutil diff --git a/usr.bin/Makefile.ia64 b/usr.bin/Makefile.ia64 index b720e3de68bf..fee2fb076811 100644 --- a/usr.bin/Makefile.ia64 +++ b/usr.bin/Makefile.ia64 @@ -1,2 +1,3 @@ # $FreeBSD$ +SUBDIR+= smbutil diff --git a/usr.bin/Makefile.powerpc b/usr.bin/Makefile.powerpc index b720e3de68bf..fee2fb076811 100644 --- a/usr.bin/Makefile.powerpc +++ b/usr.bin/Makefile.powerpc @@ -1,2 +1,3 @@ # $FreeBSD$ +SUBDIR+= smbutil diff --git a/usr.bin/Makefile.sparc64 b/usr.bin/Makefile.sparc64 index b720e3de68bf..fee2fb076811 100644 --- a/usr.bin/Makefile.sparc64 +++ b/usr.bin/Makefile.sparc64 @@ -1,2 +1,3 @@ # $FreeBSD$ +SUBDIR+= smbutil diff --git a/usr.bin/kdump/kdump.c b/usr.bin/kdump/kdump.c index 550c4cb90456..77a0caeb46d5 100644 --- a/usr.bin/kdump/kdump.c +++ b/usr.bin/kdump/kdump.c @@ -1482,6 +1482,8 @@ ktrsockaddr(struct sockaddr *sa) TODO: Support additional address families #include struct sockaddr_natm *natm; + #include + struct sockaddr_nb *nb; */ char addr[64]; diff --git a/usr.sbin/Makefile.amd64 b/usr.sbin/Makefile.amd64 index 5ee2165b38e4..b82162580bbc 100644 --- a/usr.sbin/Makefile.amd64 +++ b/usr.sbin/Makefile.amd64 @@ -20,6 +20,7 @@ SUBDIR+= btxld SUBDIR+= cpucontrol SUBDIR+= kgmon SUBDIR+= lptcontrol +SUBDIR+= mount_smbfs SUBDIR+= mptable .if ${MK_NDIS} != "no" SUBDIR+= ndiscvt diff --git a/usr.sbin/Makefile.i386 b/usr.sbin/Makefile.i386 index 901c2d938a8c..7d66f783f28a 100644 --- a/usr.sbin/Makefile.i386 +++ b/usr.sbin/Makefile.i386 @@ -12,6 +12,7 @@ SUBDIR+= cpucontrol SUBDIR+= kgmon SUBDIR+= kgzip SUBDIR+= lptcontrol +SUBDIR+= mount_smbfs SUBDIR+= mptable .if ${MK_NDIS} != "no" SUBDIR+= ndiscvt diff --git a/usr.sbin/Makefile.ia64 b/usr.sbin/Makefile.ia64 index d047b3375156..0a897b40b316 100644 --- a/usr.sbin/Makefile.ia64 +++ b/usr.sbin/Makefile.ia64 @@ -4,5 +4,6 @@ SUBDIR+= acpi .endif SUBDIR+= kgmon +SUBDIR+= mount_smbfs SUBDIR:= ${SUBDIR:Nuathload} SUBDIR+= zzz diff --git a/usr.sbin/Makefile.powerpc b/usr.sbin/Makefile.powerpc index 131eb571cdc4..8833a2741e19 100644 --- a/usr.sbin/Makefile.powerpc +++ b/usr.sbin/Makefile.powerpc @@ -1,4 +1,5 @@ # $FreeBSD$ +SUBDIR+= mount_smbfs SUBDIR+= nvram SUBDIR+= ofwdump diff --git a/usr.sbin/Makefile.sparc64 b/usr.sbin/Makefile.sparc64 index 81f7a9b953ac..632b3a83706d 100644 --- a/usr.sbin/Makefile.sparc64 +++ b/usr.sbin/Makefile.sparc64 @@ -1,4 +1,5 @@ # $FreeBSD$ SUBDIR+= eeprom +SUBDIR+= mount_smbfs SUBDIR+= ofwdump -- cgit v1.3 From 7008be5bd7341259037f383434a72960413cfeb8 Mon Sep 17 00:00:00 2001 From: Pawel Jakub Dawidek Date: Thu, 5 Sep 2013 00:09:56 +0000 Subject: Change the cap_rights_t type from uint64_t to a structure that we can extend in the future in a backward compatible (API and ABI) way. The cap_rights_t represents capability rights. We used to use one bit to represent one right, but we are running out of spare bits. Currently the new structure provides place for 114 rights (so 50 more than the previous cap_rights_t), but it is possible to grow the structure to hold at least 285 rights, although we can make it even larger if 285 rights won't be enough. The structure definition looks like this: struct cap_rights { uint64_t cr_rights[CAP_RIGHTS_VERSION + 2]; }; The initial CAP_RIGHTS_VERSION is 0. The top two bits in the first element of the cr_rights[] array contain total number of elements in the array - 2. This means if those two bits are equal to 0, we have 2 array elements. The top two bits in all remaining array elements should be 0. The next five bits in all array elements contain array index. Only one bit is used and bit position in this five-bits range defines array index. This means there can be at most five array elements in the future. To define new right the CAPRIGHT() macro must be used. The macro takes two arguments - an array index and a bit to set, eg. #define CAP_PDKILL CAPRIGHT(1, 0x0000000000000800ULL) We still support aliases that combine few rights, but the rights have to belong to the same array element, eg: #define CAP_LOOKUP CAPRIGHT(0, 0x0000000000000400ULL) #define CAP_FCHMOD CAPRIGHT(0, 0x0000000000002000ULL) #define CAP_FCHMODAT (CAP_FCHMOD | CAP_LOOKUP) There is new API to manage the new cap_rights_t structure: cap_rights_t *cap_rights_init(cap_rights_t *rights, ...); void cap_rights_set(cap_rights_t *rights, ...); void cap_rights_clear(cap_rights_t *rights, ...); bool cap_rights_is_set(const cap_rights_t *rights, ...); bool cap_rights_is_valid(const cap_rights_t *rights); void cap_rights_merge(cap_rights_t *dst, const cap_rights_t *src); void cap_rights_remove(cap_rights_t *dst, const cap_rights_t *src); bool cap_rights_contains(const cap_rights_t *big, const cap_rights_t *little); Capability rights to the cap_rights_init(), cap_rights_set(), cap_rights_clear() and cap_rights_is_set() functions are provided by separating them with commas, eg: cap_rights_t rights; cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_FSTAT); There is no need to terminate the list of rights, as those functions are actually macros that take care of the termination, eg: #define cap_rights_set(rights, ...) \ __cap_rights_set((rights), __VA_ARGS__, 0ULL) void __cap_rights_set(cap_rights_t *rights, ...); Thanks to using one bit as an array index we can assert in those functions that there are no two rights belonging to different array elements provided together. For example this is illegal and will be detected, because CAP_LOOKUP belongs to element 0 and CAP_PDKILL to element 1: cap_rights_init(&rights, CAP_LOOKUP | CAP_PDKILL); Providing several rights that belongs to the same array's element this way is correct, but is not advised. It should only be used for aliases definition. This commit also breaks compatibility with some existing Capsicum system calls, but I see no other way to do that. This should be fine as Capsicum is still experimental and this change is not going to 9.x. Sponsored by: The FreeBSD Foundation --- contrib/tcpdump/tcpdump.c | 37 ++- lib/libc/Makefile | 1 + lib/libc/capability/Makefile.inc | 19 ++ lib/libc/capability/Symbol.map | 14 + lib/libc/include/compat.h | 2 - lib/libc/sys/Symbol.map | 3 +- lib/libprocstat/libprocstat.c | 6 +- lib/libprocstat/libprocstat.h | 1 + sbin/dhclient/bpf.c | 12 +- sbin/dhclient/dhclient.c | 31 ++- sbin/hastd/subr.c | 9 +- sys/amd64/linux32/linux32_machdep.c | 5 +- sys/bsm/audit_kevents.h | 1 + sys/bsm/audit_record.h | 4 + sys/cddl/compat/opensolaris/sys/file.h | 4 +- .../opensolaris/uts/common/fs/zfs/zfs_ioctl.c | 15 +- .../opensolaris/uts/common/fs/zfs/zfs_onexit.c | 3 +- sys/compat/freebsd32/freebsd32_capability.c | 20 -- sys/compat/freebsd32/freebsd32_ioctl.c | 4 +- sys/compat/freebsd32/freebsd32_misc.c | 5 +- sys/compat/freebsd32/syscalls.master | 16 +- sys/compat/linux/linux_file.c | 17 +- sys/compat/linux/linux_ioctl.c | 82 ++++-- sys/compat/linux/linux_socket.c | 4 +- sys/compat/svr4/svr4_fcntl.c | 16 +- sys/compat/svr4/svr4_filio.c | 3 +- sys/compat/svr4/svr4_ioctl.c | 4 +- sys/compat/svr4/svr4_misc.c | 10 +- sys/compat/svr4/svr4_stream.c | 12 +- sys/conf/files | 1 + sys/dev/aac/aac_linux.c | 4 +- sys/dev/amr/amr_linux.c | 4 +- sys/dev/filemon/filemon.c | 16 +- sys/dev/hwpmc/hwpmc_logging.c | 4 +- sys/dev/ipmi/ipmi_linux.c | 4 +- sys/dev/iscsi_initiator/iscsi.c | 7 +- sys/dev/mfi/mfi_linux.c | 4 +- sys/dev/tdfx/tdfx_linux.c | 4 +- sys/fs/fdescfs/fdesc_vnops.c | 4 +- sys/fs/fuse/fuse_vfsops.c | 3 +- sys/fs/nfsclient/nfs_clport.c | 9 +- sys/fs/nfsserver/nfs_nfsdport.c | 5 +- sys/i386/ibcs2/ibcs2_fcntl.c | 4 +- sys/i386/ibcs2/ibcs2_ioctl.c | 4 +- sys/i386/ibcs2/ibcs2_misc.c | 11 +- sys/i386/linux/linux_machdep.c | 5 +- sys/kern/capabilities.conf | 3 +- sys/kern/kern_descrip.c | 137 +++++----- sys/kern/kern_event.c | 12 +- sys/kern/kern_exec.c | 4 +- sys/kern/kern_ktrace.c | 8 +- sys/kern/kern_sig.c | 4 +- sys/kern/subr_capability.c | 285 +++++++++++++++++++++ sys/kern/sys_capability.c | 170 ++++++------ sys/kern/sys_generic.c | 32 ++- sys/kern/sys_procdesc.c | 12 +- sys/kern/syscalls.master | 8 +- sys/kern/tty.c | 4 +- sys/kern/uipc_mqueue.c | 25 +- sys/kern/uipc_sem.c | 18 +- sys/kern/uipc_syscalls.c | 82 ++++-- sys/kern/uipc_usrreq.c | 8 +- sys/kern/vfs_acl.c | 18 +- sys/kern/vfs_aio.c | 11 +- sys/kern/vfs_extattr.c | 17 +- sys/kern/vfs_lookup.c | 33 ++- sys/kern/vfs_syscalls.c | 140 ++++++---- sys/netsmb/smb_dev.c | 3 +- sys/nfsserver/nfs_srvkrpc.c | 4 +- sys/security/audit/audit.h | 2 +- sys/security/audit/audit_arg.c | 4 +- sys/security/audit/audit_bsm.c | 3 +- sys/security/audit/audit_private.h | 1 + sys/security/audit/bsm_token.c | 16 ++ sys/security/mac/mac_syscalls.c | 6 +- sys/sys/_types.h | 1 - sys/sys/capability.h | 247 ++++++++++-------- sys/sys/caprights.h | 61 +++++ sys/sys/file.h | 21 +- sys/sys/filedesc.h | 9 +- sys/sys/ktrace.h | 7 +- sys/sys/namei.h | 29 +-- sys/sys/procdesc.h | 4 +- sys/sys/types.h | 9 +- sys/sys/user.h | 4 +- sys/ufs/ffs/ffs_alloc.c | 7 +- sys/vm/vm_mmap.c | 12 +- usr.bin/kdump/kdump.c | 71 +++-- usr.bin/kdump/mksubr | 24 +- usr.bin/procstat/procstat_files.c | 18 +- usr.bin/rwho/rwho.c | 7 +- usr.bin/uniq/uniq.c | 13 +- usr.sbin/rwhod/rwhod.c | 10 +- 93 files changed, 1402 insertions(+), 675 deletions(-) create mode 100644 lib/libc/capability/Makefile.inc create mode 100644 lib/libc/capability/Symbol.map create mode 100644 sys/kern/subr_capability.c create mode 100644 sys/sys/caprights.h (limited to 'lib/libprocstat') diff --git a/contrib/tcpdump/tcpdump.c b/contrib/tcpdump/tcpdump.c index 48b774df686e..afcc152142dd 100644 --- a/contrib/tcpdump/tcpdump.c +++ b/contrib/tcpdump/tcpdump.c @@ -715,8 +715,9 @@ main(int argc, char **argv) int status; FILE *VFile; #ifdef __FreeBSD__ + cap_rights_t rights; int cansandbox; -#endif +#endif /* __FreeBSD__ */ #ifdef WIN32 if(wsockinit() != 0) return 1; @@ -1206,7 +1207,8 @@ main(int argc, char **argv) if (pd == NULL) error("%s", ebuf); #ifdef __FreeBSD__ - if (cap_rights_limit(fileno(pcap_file(pd)), CAP_READ) < 0 && + cap_rights_init(&rights, CAP_READ); + if (cap_rights_limit(fileno(pcap_file(pd)), &rights) < 0 && errno != ENOSYS) { error("unable to limit pcap descriptor"); } @@ -1484,8 +1486,9 @@ main(int argc, char **argv) if (RFileName == NULL && VFileName == NULL) { static const unsigned long cmds[] = { BIOCGSTATS }; - if (cap_rights_limit(pcap_fileno(pd), - CAP_IOCTL | CAP_READ) < 0 && errno != ENOSYS) { + cap_rights_init(&rights, CAP_IOCTL, CAP_READ); + if (cap_rights_limit(pcap_fileno(pd), &rights) < 0 && + errno != ENOSYS) { error("unable to limit pcap descriptor"); } if (cap_ioctls_limit(pcap_fileno(pd), cmds, @@ -1516,8 +1519,9 @@ main(int argc, char **argv) if (p == NULL) error("%s", pcap_geterr(pd)); #ifdef __FreeBSD__ - if (cap_rights_limit(fileno(pcap_dump_file(p)), - CAP_SEEK | CAP_WRITE) < 0 && errno != ENOSYS) { + cap_rights_init(&rights, CAP_SEEK, CAP_WRITE); + if (cap_rights_limit(fileno(pcap_dump_file(p)), &rights) < 0 && + errno != ENOSYS) { error("unable to limit dump descriptor"); } #endif @@ -1530,9 +1534,10 @@ main(int argc, char **argv) error("unable to open directory %s", dirname(WFileName)); } - if (cap_rights_limit(dumpinfo.dirfd, CAP_CREATE | - CAP_FCNTL | CAP_FTRUNCATE | CAP_LOOKUP | CAP_SEEK | - CAP_WRITE) < 0 && errno != ENOSYS) { + cap_rights_init(&rights, CAP_CREATE, CAP_FCNTL, + CAP_FTRUNCATE, CAP_LOOKUP, CAP_SEEK, CAP_WRITE); + if (cap_rights_limit(dumpinfo.dirfd, &rights) < 0 && + errno != ENOSYS) { error("unable to limit directory rights"); } #else /* !__FreeBSD__ */ @@ -1615,7 +1620,7 @@ main(int argc, char **argv) error("unable to enter the capability mode"); if (cap_sandboxed()) fprintf(stderr, "capability mode sandbox enabled\n"); -#endif +#endif /* __FreeBSD__ */ do { status = pcap_loop(pd, cnt, callback, pcap_userdata); @@ -1657,8 +1662,9 @@ main(int argc, char **argv) if (pd == NULL) error("%s", ebuf); #ifdef __FreeBSD__ + cap_rights_init(&rights, CAP_READ); if (cap_rights_limit(fileno(pcap_file(pd)), - CAP_READ) < 0 && errno != ENOSYS) { + &rights) < 0 && errno != ENOSYS) { error("unable to limit pcap descriptor"); } #endif @@ -1830,6 +1836,9 @@ static void dump_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *sp) { struct dump_info *dump_info; +#ifdef __FreeBSD__ + cap_rights_t rights; +#endif ++packets_captured; @@ -1933,8 +1942,9 @@ dump_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *s if (dump_info->p == NULL) error("%s", pcap_geterr(pd)); #ifdef __FreeBSD__ + cap_rights_init(&rights, CAP_SEEK, CAP_WRITE); if (cap_rights_limit(fileno(pcap_dump_file(dump_info->p)), - CAP_SEEK | CAP_WRITE) < 0 && errno != ENOSYS) { + &rights) < 0 && errno != ENOSYS) { error("unable to limit dump descriptor"); } #endif @@ -1993,8 +2003,9 @@ dump_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *s if (dump_info->p == NULL) error("%s", pcap_geterr(pd)); #ifdef __FreeBSD__ + cap_rights_init(&rights, CAP_SEEK, CAP_WRITE); if (cap_rights_limit(fileno(pcap_dump_file(dump_info->p)), - CAP_SEEK | CAP_WRITE) < 0 && errno != ENOSYS) { + &rights) < 0 && errno != ENOSYS) { error("unable to limit dump descriptor"); } #endif diff --git a/lib/libc/Makefile b/lib/libc/Makefile index cf2d2aa52529..2806cc7083e5 100644 --- a/lib/libc/Makefile +++ b/lib/libc/Makefile @@ -100,6 +100,7 @@ NOASM= CFLAGS+= -DYP .include "${.CURDIR}/yp/Makefile.inc" .endif +.include "${.CURDIR}/capability/Makefile.inc" .if ${MK_HESIOD} != "no" CFLAGS+= -DHESIOD .endif diff --git a/lib/libc/capability/Makefile.inc b/lib/libc/capability/Makefile.inc new file mode 100644 index 000000000000..934fc8b91767 --- /dev/null +++ b/lib/libc/capability/Makefile.inc @@ -0,0 +1,19 @@ +# $FreeBSD$ + +# capability sources +.PATH: ${.CURDIR}/../../sys/kern + +SRCS+= subr_capability.c + +SYM_MAPS+= ${.CURDIR}/capability/Symbol.map + +#MAN+= cap_rights_init.3 + +#MLINKS+=cap_rights_init.3 cap_rights_set.3 +#MLINKS+=cap_rights_init.3 cap_rights_clear.3 +#MLINKS+=cap_rights_init.3 cap_rights_is_set.3 +#MLINKS+=cap_rights_init.3 cap_rights_is_valid.3 +#MLINKS+=cap_rights_init.3 cap_rights_merge.3 +#MLINKS+=cap_rights_init.3 cap_rights_remove.3 +#MLINKS+=cap_rights_init.3 cap_rights_contains.3 + diff --git a/lib/libc/capability/Symbol.map b/lib/libc/capability/Symbol.map new file mode 100644 index 000000000000..c5c18c2f5315 --- /dev/null +++ b/lib/libc/capability/Symbol.map @@ -0,0 +1,14 @@ +/* + * $FreeBSD$ + */ + +FBSD_1.3 { + __cap_rights_clear; + cap_rights_contains; + __cap_rights_init; + __cap_rights_is_set; + cap_rights_is_valid; + cap_rights_merge; + cap_rights_remove; + __cap_rights_set; +}; diff --git a/lib/libc/include/compat.h b/lib/libc/include/compat.h index 3739fe105c8f..769454002788 100644 --- a/lib/libc/include/compat.h +++ b/lib/libc/include/compat.h @@ -42,8 +42,6 @@ __sym_compat(__semctl, freebsd7___semctl, FBSD_1.0); __sym_compat(msgctl, freebsd7_msgctl, FBSD_1.0); __sym_compat(shmctl, freebsd7_shmctl, FBSD_1.0); -__sym_compat(cap_getrights, cap_rights_get, FBSD_1.2); - #undef __sym_compat #endif /* __LIBC_COMPAT_H__ */ diff --git a/lib/libc/sys/Symbol.map b/lib/libc/sys/Symbol.map index 4f1104e170be..222f5f0811f5 100644 --- a/lib/libc/sys/Symbol.map +++ b/lib/libc/sys/Symbol.map @@ -363,7 +363,6 @@ FBSD_1.1 { FBSD_1.2 { cap_enter; cap_getmode; - cap_new; getloginclass; pdfork; pdgetpid; @@ -385,7 +384,7 @@ FBSD_1.3 { cap_fcntls_limit; cap_ioctls_get; cap_ioctls_limit; - cap_rights_get; + __cap_rights_get; cap_rights_limit; cap_sandboxed; chflagsat; diff --git a/lib/libprocstat/libprocstat.c b/lib/libprocstat/libprocstat.c index dfb5ed328194..9056151e2b4d 100644 --- a/lib/libprocstat/libprocstat.c +++ b/lib/libprocstat/libprocstat.c @@ -378,7 +378,7 @@ procstat_freefiles(struct procstat *procstat, struct filestat_list *head) static struct filestat * filestat_new_entry(void *typedep, int type, int fd, int fflags, int uflags, - int refcount, off_t offset, char *path, cap_rights_t cap_rights) + int refcount, off_t offset, char *path, cap_rights_t *cap_rightsp) { struct filestat *entry; @@ -395,7 +395,7 @@ filestat_new_entry(void *typedep, int type, int fd, int fflags, int uflags, entry->fs_ref_count = refcount; entry->fs_offset = offset; entry->fs_path = path; - entry->fs_cap_rights = cap_rights; + entry->fs_cap_rights = *cap_rightsp; return (entry); } @@ -851,7 +851,7 @@ procstat_getfiles_sysctl(struct procstat *procstat, struct kinfo_proc *kp, * Create filestat entry. */ entry = filestat_new_entry(kif, type, fd, fflags, uflags, - refcount, offset, path, cap_rights); + refcount, offset, path, &cap_rights); if (entry != NULL) STAILQ_INSERT_TAIL(head, entry, next); } diff --git a/lib/libprocstat/libprocstat.h b/lib/libprocstat/libprocstat.h index 65a5eb955324..7af6ccba14a2 100644 --- a/lib/libprocstat/libprocstat.h +++ b/lib/libprocstat/libprocstat.h @@ -36,6 +36,7 @@ #ifndef ZFS #include #endif +#include /* * Vnode types. diff --git a/sbin/dhclient/bpf.c b/sbin/dhclient/bpf.c index f43502832ef5..c0a172039116 100644 --- a/sbin/dhclient/bpf.c +++ b/sbin/dhclient/bpf.c @@ -43,6 +43,8 @@ #include __FBSDID("$FreeBSD$"); +#include + #include "dhcpd.h" #include "privsep.h" #include @@ -132,6 +134,7 @@ int dhcp_bpf_wfilter_len = sizeof(dhcp_bpf_wfilter) / sizeof(struct bpf_insn); void if_register_send(struct interface_info *info) { + cap_rights_t rights; struct bpf_version v; struct bpf_program p; int sock, on = 1; @@ -160,7 +163,8 @@ if_register_send(struct interface_info *info) if (ioctl(info->wfdesc, BIOCLOCK, NULL) < 0) error("Cannot lock bpf"); - if (cap_rights_limit(info->wfdesc, CAP_WRITE) < 0 && errno != ENOSYS) + cap_rights_init(&rights, CAP_WRITE); + if (cap_rights_limit(info->wfdesc, &rights) < 0 && errno != ENOSYS) error("Can't limit bpf descriptor: %m"); /* @@ -213,6 +217,7 @@ void if_register_receive(struct interface_info *info) { static const unsigned long cmds[2] = { SIOCGIFFLAGS, SIOCGIFMEDIA }; + cap_rights_t rights; struct bpf_version v; struct bpf_program p; int flag = 1, sz; @@ -264,10 +269,9 @@ if_register_receive(struct interface_info *info) if (ioctl(info->rfdesc, BIOCLOCK, NULL) < 0) error("Cannot lock bpf"); - if (cap_rights_limit(info->rfdesc, - CAP_IOCTL | CAP_POLL_EVENT | CAP_READ) < 0 && errno != ENOSYS) { + cap_rights_init(&rights, CAP_IOCTL, CAP_POLL_EVENT, CAP_READ); + if (cap_rights_limit(info->rfdesc, &rights) < 0 && errno != ENOSYS) error("Can't limit bpf descriptor: %m"); - } if (cap_ioctls_limit(info->rfdesc, cmds, 2) < 0 && errno != ENOSYS) error("Can't limit ioctls for bpf descriptor: %m"); } diff --git a/sbin/dhclient/dhclient.c b/sbin/dhclient/dhclient.c index c8f05b503d34..e16e464c6002 100644 --- a/sbin/dhclient/dhclient.c +++ b/sbin/dhclient/dhclient.c @@ -56,6 +56,8 @@ #include __FBSDID("$FreeBSD$"); +#include + #include "dhcpd.h" #include "privsep.h" @@ -346,6 +348,7 @@ main(int argc, char *argv[]) int immediate_daemon = 0; struct passwd *pw; pid_t otherpid; + cap_rights_t rights; /* Initially, log errors to stderr as well as to syslogd. */ openlog(__progname, LOG_PID | LOG_NDELAY, DHCPD_LOG_FACILITY); @@ -477,10 +480,9 @@ main(int argc, char *argv[]) close(pipe_fd[0]); privfd = pipe_fd[1]; - if (cap_rights_limit(privfd, CAP_READ | CAP_WRITE) < 0 && - errno != ENOSYS) { + cap_rights_init(&rights, CAP_READ, CAP_WRITE); + if (cap_rights_limit(privfd, &rights) < 0 && errno != ENOSYS) error("can't limit private descriptor: %m"); - } if ((fd = open(path_dhclient_db, O_RDONLY|O_EXLOCK|O_CREAT, 0)) == -1) error("can't open and lock %s: %m", path_dhclient_db); @@ -492,10 +494,9 @@ main(int argc, char *argv[]) add_protocol("AF_ROUTE", routefd, routehandler, ifi); if (shutdown(routefd, SHUT_WR) < 0) error("can't shutdown route socket: %m"); - if (cap_rights_limit(routefd, CAP_POLL_EVENT | CAP_READ) < 0 && - errno != ENOSYS) { + cap_rights_init(&rights, CAP_POLL_EVENT, CAP_READ); + if (cap_rights_limit(routefd, &rights) < 0 && errno != ENOSYS) error("can't limit route socket: %m"); - } if (chroot(_PATH_VAREMPTY) == -1) error("chroot"); @@ -1840,13 +1841,15 @@ void rewrite_client_leases(void) { struct client_lease *lp; + cap_rights_t rights; if (!leaseFile) { leaseFile = fopen(path_dhclient_db, "w"); if (!leaseFile) error("can't create %s: %m", path_dhclient_db); - if (cap_rights_limit(fileno(leaseFile), CAP_FSTAT | CAP_FSYNC | - CAP_FTRUNCATE | CAP_SEEK | CAP_WRITE) < 0 && + cap_rights_init(&rights, CAP_FSTAT, CAP_FSYNC, CAP_FTRUNCATE, + CAP_SEEK, CAP_WRITE); + if (cap_rights_limit(fileno(leaseFile), &rights) < 0 && errno != ENOSYS) { error("can't limit lease descriptor: %m"); } @@ -2354,6 +2357,7 @@ void go_daemon(void) { static int state = 0; + cap_rights_t rights; if (no_daemon || state) return; @@ -2366,9 +2370,11 @@ go_daemon(void) if (daemon(1, 0) == -1) error("daemon"); + cap_rights_init(&rights); + if (pidfile != NULL) { pidfile_write(pidfile); - if (cap_rights_limit(pidfile_fileno(pidfile), CAP_NONE) < 0 && + if (cap_rights_limit(pidfile_fileno(pidfile), &rights) < 0 && errno != ENOSYS) { error("can't limit pidfile descriptor: %m"); } @@ -2383,11 +2389,12 @@ go_daemon(void) nullfd = -1; } - if (cap_rights_limit(STDIN_FILENO, CAP_NONE) < 0 && errno != ENOSYS) + if (cap_rights_limit(STDIN_FILENO, &rights) < 0 && errno != ENOSYS) error("can't limit stdin: %m"); - if (cap_rights_limit(STDOUT_FILENO, CAP_WRITE) < 0 && errno != ENOSYS) + cap_rights_init(&rights, CAP_WRITE); + if (cap_rights_limit(STDOUT_FILENO, &rights) < 0 && errno != ENOSYS) error("can't limit stdout: %m"); - if (cap_rights_limit(STDERR_FILENO, CAP_WRITE) < 0 && errno != ENOSYS) + if (cap_rights_limit(STDERR_FILENO, &rights) < 0 && errno != ENOSYS) error("can't limit stderr: %m"); } diff --git a/sbin/hastd/subr.c b/sbin/hastd/subr.c index 440061e8c364..0e9930bcb7fa 100644 --- a/sbin/hastd/subr.c +++ b/sbin/hastd/subr.c @@ -231,6 +231,7 @@ drop_privs(const struct hast_resource *res) pjdlog_common(LOG_DEBUG, 1, errno, "Unable to sandbox using capsicum"); } else if (res != NULL) { + cap_rights_t rights; static const unsigned long geomcmds[] = { DIOCGDELETE, DIOCGFLUSH @@ -239,8 +240,9 @@ drop_privs(const struct hast_resource *res) PJDLOG_ASSERT(res->hr_role == HAST_ROLE_PRIMARY || res->hr_role == HAST_ROLE_SECONDARY); - if (cap_rights_limit(res->hr_localfd, - CAP_FLOCK | CAP_IOCTL | CAP_PREAD | CAP_PWRITE) == -1) { + cap_rights_init(&rights, CAP_FLOCK, CAP_IOCTL, CAP_PREAD, + CAP_PWRITE); + if (cap_rights_limit(res->hr_localfd, &rights) == -1) { pjdlog_errno(LOG_ERR, "Unable to limit capability rights on local descriptor"); } @@ -258,7 +260,8 @@ drop_privs(const struct hast_resource *res) G_GATE_CMD_DESTROY }; - if (cap_rights_limit(res->hr_ggatefd, CAP_IOCTL) == -1) { + cap_rights_init(&rights, CAP_IOCTL); + if (cap_rights_limit(res->hr_ggatefd, &rights) == -1) { pjdlog_errno(LOG_ERR, "Unable to limit capability rights to CAP_IOCTL on ggate descriptor"); } diff --git a/sys/amd64/linux32/linux32_machdep.c b/sys/amd64/linux32/linux32_machdep.c index 65f034acc0de..3dd8f7a09987 100644 --- a/sys/amd64/linux32/linux32_machdep.c +++ b/sys/amd64/linux32/linux32_machdep.c @@ -519,6 +519,7 @@ linux_mmap_common(struct thread *td, l_uintptr_t addr, l_size_t len, l_int prot, } */ bsd_args; int error; struct file *fp; + cap_rights_t rights; error = 0; bsd_args.flags = 0; @@ -567,7 +568,9 @@ linux_mmap_common(struct thread *td, l_uintptr_t addr, l_size_t len, l_int prot, * protection options specified. */ - if ((error = fget(td, bsd_args.fd, CAP_MMAP, &fp)) != 0) + error = fget(td, bsd_args.fd, + cap_rights_init(&rights, CAP_MMAP), &fp); + if (error != 0) return (error); if (fp->f_type != DTYPE_VNODE) { fdrop(fp, td); diff --git a/sys/bsm/audit_kevents.h b/sys/bsm/audit_kevents.h index da2bc7c00c55..303d37ff80f2 100644 --- a/sys/bsm/audit_kevents.h +++ b/sys/bsm/audit_kevents.h @@ -589,6 +589,7 @@ #define AUE_POSIX_OPENPT 43185 /* FreeBSD. */ #define AUE_CAP_NEW 43186 /* TrustedBSD. */ #define AUE_CAP_RIGHTS_GET 43187 /* TrustedBSD. */ +#define AUE_CAP_GETRIGHTS AUE_CAP_RIGHTS_GET #define AUE_CAP_ENTER 43188 /* TrustedBSD. */ #define AUE_CAP_GETMODE 43189 /* TrustedBSD. */ #define AUE_POSIX_SPAWN 43190 /* Darwin. */ diff --git a/sys/bsm/audit_record.h b/sys/bsm/audit_record.h index 706c6f36ed1b..7e6074f3d344 100644 --- a/sys/bsm/audit_record.h +++ b/sys/bsm/audit_record.h @@ -34,6 +34,7 @@ #define _BSM_AUDIT_RECORD_H_ #include /* struct timeval */ +#include /* cap_rights_t */ /* * Token type identifiers. @@ -126,6 +127,8 @@ #define AUT_SOCKINET128 0x81 /* XXX */ #define AUT_SOCKUNIX 0x82 /* XXX */ +#define AUT_RIGHTS 0x83 + /* print values for the arbitrary token */ #define AUP_BINARY 0 #define AUP_OCTAL 1 @@ -248,6 +251,7 @@ token_t *au_to_process32_ex(au_id_t auid, uid_t euid, gid_t egid, au_tid_addr_t *tid); token_t *au_to_process64_ex(au_id_t auid, uid_t euid, gid_t egid, uid_t ruid, gid_t rgid, pid_t pid, au_asid_t sid, au_tid_addr_t *tid); +token_t *au_to_rights(cap_rights_t *rightsp); token_t *au_to_return(char status, uint32_t ret); token_t *au_to_return32(char status, uint32_t ret); token_t *au_to_return64(char status, uint64_t ret); diff --git a/sys/cddl/compat/opensolaris/sys/file.h b/sys/cddl/compat/opensolaris/sys/file.h index 0b8f87506614..a1c1d4521992 100644 --- a/sys/cddl/compat/opensolaris/sys/file.h +++ b/sys/cddl/compat/opensolaris/sys/file.h @@ -39,11 +39,11 @@ typedef struct file file_t; #include static __inline file_t * -getf(int fd, cap_rights_t rights) +getf(int fd, cap_rights_t *rightsp) { struct file *fp; - if (fget(curthread, fd, rights, &fp) == 0) + if (fget(curthread, fd, rightsp, &fp) == 0) return (fp); return (NULL); } diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c index 10456f886061..e9fba26d8365 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c @@ -4005,6 +4005,7 @@ zfs_ioc_recv(zfs_cmd_t *zc) char *origin = NULL; char *tosnap; char tofs[ZFS_MAXNAMELEN]; + cap_rights_t rights; boolean_t first_recvd_props = B_FALSE; if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 || @@ -4022,7 +4023,7 @@ zfs_ioc_recv(zfs_cmd_t *zc) return (error); fd = zc->zc_cookie; - fp = getf(fd, CAP_PREAD); + fp = getf(fd, cap_rights_init(&rights, CAP_PREAD)); if (fp == NULL) { nvlist_free(props); return (SET_ERROR(EBADF)); @@ -4260,7 +4261,11 @@ zfs_ioc_send(zfs_cmd_t *zc) dsl_dataset_rele(tosnap, FTAG); dsl_pool_rele(dp, FTAG); } else { - file_t *fp = getf(zc->zc_cookie, CAP_WRITE); + file_t *fp; + cap_rights_t rights; + + fp = getf(zc->zc_cookie, + cap_rights_init(&rights, CAP_WRITE)); if (fp == NULL) return (SET_ERROR(EBADF)); @@ -4851,10 +4856,11 @@ static int zfs_ioc_diff(zfs_cmd_t *zc) { file_t *fp; + cap_rights_t rights; offset_t off; int error; - fp = getf(zc->zc_cookie, CAP_WRITE); + fp = getf(zc->zc_cookie, cap_rights_init(&rights, CAP_WRITE)); if (fp == NULL) return (SET_ERROR(EBADF)); @@ -5214,6 +5220,7 @@ zfs_ioc_unjail(zfs_cmd_t *zc) static int zfs_ioc_send_new(const char *snapname, nvlist_t *innvl, nvlist_t *outnvl) { + cap_rights_t rights; int error; offset_t off; char *fromname = NULL; @@ -5225,7 +5232,7 @@ zfs_ioc_send_new(const char *snapname, nvlist_t *innvl, nvlist_t *outnvl) (void) nvlist_lookup_string(innvl, "fromsnap", &fromname); - file_t *fp = getf(fd, CAP_READ); + file_t *fp = getf(fd, cap_rights_init(&rights, CAP_READ)); if (fp == NULL) return (SET_ERROR(EBADF)); diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_onexit.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_onexit.c index 05252cbd0645..6a90b9cf2028 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_onexit.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_onexit.c @@ -122,10 +122,11 @@ zfs_onexit_fd_hold(int fd, minor_t *minorp) { file_t *fp, *tmpfp; zfs_onexit_t *zo; + cap_rights_t rights; void *data; int error; - fp = getf(fd, CAP_NONE); + fp = getf(fd, cap_rights_init(&rights)); if (fp == NULL) return (SET_ERROR(EBADF)); diff --git a/sys/compat/freebsd32/freebsd32_capability.c b/sys/compat/freebsd32/freebsd32_capability.c index e17c39417ffc..b23cf959d125 100644 --- a/sys/compat/freebsd32/freebsd32_capability.c +++ b/sys/compat/freebsd32/freebsd32_capability.c @@ -42,24 +42,12 @@ __FBSDID("$FreeBSD$"); #include -#include #include #ifdef CAPABILITIES MALLOC_DECLARE(M_FILECAPS); -int -freebsd32_cap_rights_limit(struct thread *td, - struct freebsd32_cap_rights_limit_args *uap) -{ - struct cap_rights_limit_args ap; - - ap.fd = uap->fd; - ap.rights = PAIR32TO64(uint64_t, uap->rights); - return (sys_cap_rights_limit(td, &ap)); -} - int freebsd32_cap_ioctls_limit(struct thread *td, struct freebsd32_cap_ioctls_limit_args *uap) @@ -147,14 +135,6 @@ out: #else /* !CAPABILITIES */ -int -freebsd32_cap_rights_limit(struct thread *td, - struct freebsd32_cap_rights_limit_args *uap) -{ - - return (ENOSYS); -} - int freebsd32_cap_ioctls_limit(struct thread *td, struct freebsd32_cap_ioctls_limit_args *uap) diff --git a/sys/compat/freebsd32/freebsd32_ioctl.c b/sys/compat/freebsd32/freebsd32_ioctl.c index 81f5c8ed4715..1f90e58541b6 100644 --- a/sys/compat/freebsd32/freebsd32_ioctl.c +++ b/sys/compat/freebsd32/freebsd32_ioctl.c @@ -353,9 +353,11 @@ freebsd32_ioctl(struct thread *td, struct freebsd32_ioctl_args *uap) caddr_t data; }*/ ; struct file *fp; + cap_rights_t rights; int error; - if ((error = fget(td, uap->fd, CAP_IOCTL, &fp)) != 0) + error = fget(td, uap->fd, cap_rights_init(&rights, CAP_IOCTL), &fp); + if (error != 0) return (error); if ((fp->f_flag & (FREAD | FWRITE)) == 0) { fdrop(fp, td); diff --git a/sys/compat/freebsd32/freebsd32_misc.c b/sys/compat/freebsd32/freebsd32_misc.c index 16d12053e5e5..a3cf5cfd6391 100644 --- a/sys/compat/freebsd32/freebsd32_misc.c +++ b/sys/compat/freebsd32/freebsd32_misc.c @@ -1650,6 +1650,7 @@ freebsd32_do_sendfile(struct thread *td, struct uio *hdr_uio, *trl_uio; struct iovec32 *iov32; struct file *fp; + cap_rights_t rights; off_t offset; int error; @@ -1686,8 +1687,10 @@ freebsd32_do_sendfile(struct thread *td, AUDIT_ARG_FD(uap->fd); - if ((error = fget_read(td, uap->fd, CAP_PREAD, &fp)) != 0) + if ((error = fget_read(td, uap->fd, + cap_rights_init(&rights, CAP_PREAD), &fp)) != 0) { goto out; + } error = fo_sendfile(fp, uap->s, hdr_uio, trl_uio, offset, uap->nbytes, uap->sbytes, uap->flags, compat ? SFK_COMPAT : 0, td); diff --git a/sys/compat/freebsd32/syscalls.master b/sys/compat/freebsd32/syscalls.master index a2e3e7836e6a..f537a5411a37 100644 --- a/sys/compat/freebsd32/syscalls.master +++ b/sys/compat/freebsd32/syscalls.master @@ -970,9 +970,9 @@ 512 AUE_SHMCTL NOSTD { int freebsd32_shmctl(int shmid, int cmd, \ struct shmid_ds32 *buf); } 513 AUE_LPATHCONF NOPROTO { int lpathconf(char *path, int name); } -514 AUE_CAP_NEW NOPROTO { int cap_new(int fd, uint64_t rights); } -515 AUE_CAP_RIGHTS_GET NOPROTO { int cap_rights_get(int fd, \ - uint64_t *rightsp); } +514 AUE_NULL OBSOL cap_new +515 AUE_CAP_RIGHTS_GET NOPROTO { int __cap_rights_get(int version, \ + int fd, cap_rights_t *rightsp); } 516 AUE_CAP_ENTER NOPROTO { int cap_enter(void); } 517 AUE_CAP_GETMODE NOPROTO { int cap_getmode(u_int *modep); } 518 AUE_PDFORK NOPROTO { int pdfork(int *fdp, int flags); } @@ -1016,10 +1016,6 @@ int *status, int options, \ struct wrusage32 *wrusage, \ siginfo_t *info); } -533 AUE_CAP_RIGHTS_LIMIT STD { \ - int freebsd32_cap_rights_limit(int fd, \ - int pad, \ - uint32_t rights1, uint32_t rights2); } #else 530 AUE_NULL STD { int freebsd32_posix_fallocate(int fd,\ uint32_t offset1, uint32_t offset2,\ @@ -1033,10 +1029,10 @@ int *status, int options, \ struct wrusage32 *wrusage, \ siginfo_t *info); } -533 AUE_CAP_RIGHTS_LIMIT STD { \ - int freebsd32_cap_rights_limit(int fd, \ - uint32_t rights1, uint32_t rights2); } #endif +533 AUE_CAP_RIGHTS_LIMIT NOPROTO { \ + int cap_rights_limit(int fd, \ + cap_rights_t *rightsp); } 534 AUE_CAP_IOCTLS_LIMIT STD { \ int freebsd32_cap_ioctls_limit(int fd, \ const uint32_t *cmds, size_t ncmds); } diff --git a/sys/compat/linux/linux_file.c b/sys/compat/linux/linux_file.c index 49c3fdf14d30..a6b1d35e4f19 100644 --- a/sys/compat/linux/linux_file.c +++ b/sys/compat/linux/linux_file.c @@ -92,6 +92,7 @@ linux_creat(struct thread *td, struct linux_creat_args *args) static int linux_common_open(struct thread *td, int dirfd, char *path, int l_flags, int mode) { + cap_rights_t rights; struct proc *p = td->td_proc; struct file *fp; int fd; @@ -143,7 +144,7 @@ linux_common_open(struct thread *td, int dirfd, char *path, int l_flags, int mod * having the same filedesc could use that fd without * checking below. */ - error = fget(td, fd, CAP_IOCTL, &fp); + error = fget(td, fd, cap_rights_init(&rights, CAP_IOCTL), &fp); if (!error) { sx_slock(&proctree_lock); PROC_LOCK(p); @@ -328,6 +329,7 @@ getdents_common(struct thread *td, struct linux_getdents64_args *args, caddr_t outp; /* Linux-format */ int resid, linuxreclen=0; /* Linux-format */ caddr_t lbuf; /* Linux-format */ + cap_rights_t rights; struct file *fp; struct uio auio; struct iovec aiov; @@ -348,7 +350,9 @@ getdents_common(struct thread *td, struct linux_getdents64_args *args, } else justone = 0; - if ((error = getvnode(td->td_proc->p_fd, args->fd, CAP_READ, &fp)) != 0) + error = getvnode(td->td_proc->p_fd, args->fd, + cap_rights_init(&rights, CAP_READ), &fp); + if (error != 0) return (error); if ((fp->f_flag & FREAD) == 0) { @@ -1024,6 +1028,7 @@ linux_pread(td, uap) struct linux_pread_args *uap; { struct pread_args bsd; + cap_rights_t rights; struct vnode *vp; int error; @@ -1036,7 +1041,9 @@ linux_pread(td, uap) if (error == 0) { /* This seems to violate POSIX but linux does it */ - if ((error = fgetvp(td, uap->fd, CAP_PREAD, &vp)) != 0) + error = fgetvp(td, uap->fd, + cap_rights_init(&rights, CAP_PREAD), &vp); + if (error != 0) return (error); if (vp->v_type == VDIR) { vrele(vp); @@ -1283,6 +1290,7 @@ fcntl_common(struct thread *td, struct linux_fcntl64_args *args) { struct l_flock linux_flock; struct flock bsd_flock; + cap_rights_t rights; struct file *fp; long arg; int error, result; @@ -1385,7 +1393,8 @@ fcntl_common(struct thread *td, struct linux_fcntl64_args *args) * significant effect for pipes (SIGIO is not delivered for * pipes under Linux-2.2.35 at least). */ - error = fget(td, args->fd, CAP_FCNTL, &fp); + error = fget(td, args->fd, + cap_rights_init(&rights, CAP_FCNTL), &fp); if (error) return (error); if (fp->f_type == DTYPE_PIPE) { diff --git a/sys/compat/linux/linux_ioctl.c b/sys/compat/linux/linux_ioctl.c index 4df28aab27cc..2a4016a30553 100644 --- a/sys/compat/linux/linux_ioctl.c +++ b/sys/compat/linux/linux_ioctl.c @@ -189,12 +189,14 @@ struct linux_hd_big_geometry { static int linux_ioctl_hdio(struct thread *td, struct linux_ioctl_args *args) { + cap_rights_t rights; struct file *fp; int error; u_int sectorsize, fwcylinders, fwheads, fwsectors; off_t mediasize, bytespercyl; - if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) + error = fget(td, args->fd, cap_rights_init(&rights, CAP_IOCTL), &fp); + if (error != 0) return (error); switch (args->cmd & 0xffff) { case LINUX_HDIO_GET_GEO: @@ -270,12 +272,14 @@ linux_ioctl_hdio(struct thread *td, struct linux_ioctl_args *args) static int linux_ioctl_disk(struct thread *td, struct linux_ioctl_args *args) { + cap_rights_t rights; struct file *fp; int error; u_int sectorsize; off_t mediasize; - if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) + error = fget(td, args->fd, cap_rights_init(&rights, CAP_IOCTL), &fp); + if (error != 0) return (error); switch (args->cmd & 0xffff) { case LINUX_BLKGETSIZE: @@ -698,10 +702,12 @@ linux_ioctl_termio(struct thread *td, struct linux_ioctl_args *args) struct termios bios; struct linux_termios lios; struct linux_termio lio; + cap_rights_t rights; struct file *fp; int error; - if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) + error = fget(td, args->fd, cap_rights_init(&rights, CAP_IOCTL), &fp); + if (error != 0) return (error); switch (args->cmd & 0xffff) { @@ -1438,10 +1444,12 @@ bsd_to_linux_dvd_authinfo(struct dvd_authinfo *bp, l_dvd_authinfo *lp) static int linux_ioctl_cdrom(struct thread *td, struct linux_ioctl_args *args) { + cap_rights_t rights; struct file *fp; int error; - if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) + error = fget(td, args->fd, cap_rights_init(&rights, CAP_IOCTL), &fp); + if (error != 0) return (error); switch (args->cmd & 0xffff) { @@ -1963,10 +1971,12 @@ linux_ioctl_sound(struct thread *td, struct linux_ioctl_args *args) static int linux_ioctl_console(struct thread *td, struct linux_ioctl_args *args) { + cap_rights_t rights; struct file *fp; int error; - if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) + error = fget(td, args->fd, cap_rights_init(&rights, CAP_IOCTL), &fp); + if (error != 0) return (error); switch (args->cmd & 0xffff) { @@ -2351,6 +2361,7 @@ static int linux_ioctl_socket(struct thread *td, struct linux_ioctl_args *args) { char lifname[LINUX_IFNAMSIZ], ifname[IFNAMSIZ]; + cap_rights_t rights; struct ifnet *ifp; struct file *fp; int error, type; @@ -2358,7 +2369,8 @@ linux_ioctl_socket(struct thread *td, struct linux_ioctl_args *args) ifp = NULL; error = 0; - if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) + error = fget(td, args->fd, cap_rights_init(&rights, CAP_IOCTL), &fp); + if (error != 0) return (error); type = fp->f_type; fdrop(fp, td); @@ -2581,10 +2593,12 @@ linux_ioctl_socket(struct thread *td, struct linux_ioctl_args *args) static int linux_ioctl_private(struct thread *td, struct linux_ioctl_args *args) { + cap_rights_t rights; struct file *fp; int error, type; - if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) + error = fget(td, args->fd, cap_rights_init(&rights, CAP_IOCTL), &fp); + if (error != 0) return (error); type = fp->f_type; fdrop(fp, td); @@ -2606,11 +2620,13 @@ linux_ioctl_drm(struct thread *td, struct linux_ioctl_args *args) static int linux_ioctl_sg(struct thread *td, struct linux_ioctl_args *args) { + cap_rights_t rights; struct file *fp; u_long cmd; int error; - if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) { + error = fget(td, args->fd, cap_rights_init(&rights, CAP_IOCTL), &fp); + if (error != 0) { printf("sg_linux_ioctl: fget returned %d\n", error); return (error); } @@ -2828,6 +2844,7 @@ linux_v4l_cliplist_copy(struct l_video_window *lvw, struct video_window *vw) static int linux_ioctl_v4l(struct thread *td, struct linux_ioctl_args *args) { + cap_rights_t rights; struct file *fp; int error; struct video_tuner vtun; @@ -2845,7 +2862,9 @@ linux_ioctl_v4l(struct thread *td, struct linux_ioctl_args *args) case LINUX_VIDIOCSCHAN: args->cmd = VIDIOCSCHAN; break; case LINUX_VIDIOCGTUNER: - if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) + error = fget(td, args->fd, + cap_rights_init(&rights, CAP_IOCTL), &fp); + if (error != 0) return (error); error = copyin((void *) args->arg, &l_vtun, sizeof(l_vtun)); if (error) { @@ -2863,7 +2882,9 @@ linux_ioctl_v4l(struct thread *td, struct linux_ioctl_args *args) return (error); case LINUX_VIDIOCSTUNER: - if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) + error = fget(td, args->fd, + cap_rights_init(&rights, CAP_IOCTL), &fp); + if (error != 0) return (error); error = copyin((void *) args->arg, &l_vtun, sizeof(l_vtun)); if (error) { @@ -2880,7 +2901,9 @@ linux_ioctl_v4l(struct thread *td, struct linux_ioctl_args *args) case LINUX_VIDIOCCAPTURE: args->cmd = VIDIOCCAPTURE; break; case LINUX_VIDIOCGWIN: - if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) + error = fget(td, args->fd, + cap_rights_init(&rights, CAP_IOCTL), &fp); + if (error != 0) return (error); error = fo_ioctl(fp, VIDIOCGWIN, &vwin, td->td_ucred, td); if (!error) { @@ -2892,7 +2915,9 @@ linux_ioctl_v4l(struct thread *td, struct linux_ioctl_args *args) return (error); case LINUX_VIDIOCSWIN: - if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) + error = fget(td, args->fd, + cap_rights_init(&rights, CAP_IOCTL), &fp); + if (error != 0) return (error); error = copyin((void *) args->arg, &l_vwin, sizeof(l_vwin)); if (error) { @@ -2915,7 +2940,9 @@ linux_ioctl_v4l(struct thread *td, struct linux_ioctl_args *args) return (error); case LINUX_VIDIOCGFBUF: - if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) + error = fget(td, args->fd, + cap_rights_init(&rights, CAP_IOCTL), &fp); + if (error != 0) return (error); error = fo_ioctl(fp, VIDIOCGFBUF, &vbuf, td->td_ucred, td); if (!error) { @@ -2927,7 +2954,9 @@ linux_ioctl_v4l(struct thread *td, struct linux_ioctl_args *args) return (error); case LINUX_VIDIOCSFBUF: - if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) + error = fget(td, args->fd, + cap_rights_init(&rights, CAP_IOCTL), &fp); + if (error != 0) return (error); error = copyin((void *) args->arg, &l_vbuf, sizeof(l_vbuf)); if (error) { @@ -2955,7 +2984,9 @@ linux_ioctl_v4l(struct thread *td, struct linux_ioctl_args *args) case LINUX_VIDIOCGPLAYINFO: args->cmd = VIDIOCGPLAYINFO; break; case LINUX_VIDIOCSMICROCODE: - if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) + error = fget(td, args->fd, + cap_rights_init(&rights, CAP_IOCTL), &fp); + if (error != 0) return (error); error = copyin((void *) args->arg, &l_vcode, sizeof(l_vcode)); if (error) { @@ -3108,6 +3139,7 @@ bsd_to_linux_v4l2_format(struct v4l2_format *vf, struct l_v4l2_format *lvf) static int linux_ioctl_v4l2(struct thread *td, struct linux_ioctl_args *args) { + cap_rights_t rights; struct file *fp; int error; struct v4l2_format vformat; @@ -3199,7 +3231,9 @@ linux_ioctl_v4l2(struct thread *td, struct linux_ioctl_args *args) error = copyin((void *)args->arg, &l_vformat, sizeof(l_vformat)); if (error) return (error); - if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) + error = fget(td, args->fd, + cap_rights_init(&rights, CAP_IOCTL), &fp); + if (error) return (error); if (linux_to_bsd_v4l2_format(&l_vformat, &vformat) != 0) error = EINVAL; @@ -3222,7 +3256,9 @@ linux_ioctl_v4l2(struct thread *td, struct linux_ioctl_args *args) if (error) return (error); linux_to_bsd_v4l2_standard(&l_vstd, &vstd); - if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) + error = fget(td, args->fd, + cap_rights_init(&rights, CAP_IOCTL), &fp); + if (error) return (error); error = fo_ioctl(fp, VIDIOC_ENUMSTD, (caddr_t)&vstd, td->td_ucred, td); @@ -3244,7 +3280,9 @@ linux_ioctl_v4l2(struct thread *td, struct linux_ioctl_args *args) sizeof(struct l_v4l2_input)); if (error != 0) return (error); - if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) + error = fget(td, args->fd, + cap_rights_init(&rights, CAP_IOCTL), &fp); + if (error != 0) return (error); error = fo_ioctl(fp, VIDIOC_ENUMINPUT, (caddr_t)&vinp, td->td_ucred, td); @@ -3263,7 +3301,9 @@ linux_ioctl_v4l2(struct thread *td, struct linux_ioctl_args *args) error = copyin((void *)args->arg, &l_vbuf, sizeof(l_vbuf)); if (error) return (error); - if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) + error = fget(td, args->fd, + cap_rights_init(&rights, CAP_IOCTL), &fp); + if (error) return (error); linux_to_bsd_v4l2_buffer(&l_vbuf, &vbuf); if ((args->cmd & 0xffff) == LINUX_VIDIOC_QUERYBUF) @@ -3432,6 +3472,7 @@ linux_ioctl_fbsd_usb(struct thread *td, struct linux_ioctl_args *args) int linux_ioctl(struct thread *td, struct linux_ioctl_args *args) { + cap_rights_t rights; struct file *fp; struct handler_element *he; int error, cmd; @@ -3442,7 +3483,8 @@ linux_ioctl(struct thread *td, struct linux_ioctl_args *args) (unsigned long)args->cmd); #endif - if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) + error = fget(td, args->fd, cap_rights_init(&rights, CAP_IOCTL), &fp); + if (error != 0) return (error); if ((fp->f_flag & (FREAD|FWRITE)) == 0) { fdrop(fp, td); diff --git a/sys/compat/linux/linux_socket.c b/sys/compat/linux/linux_socket.c index 36b23acec4a6..22f811c50a77 100644 --- a/sys/compat/linux/linux_socket.c +++ b/sys/compat/linux/linux_socket.c @@ -748,6 +748,7 @@ int linux_connect(struct thread *, struct linux_connect_args *); int linux_connect(struct thread *td, struct linux_connect_args *args) { + cap_rights_t rights; struct socket *so; struct sockaddr *sa; u_int fflag; @@ -772,7 +773,8 @@ linux_connect(struct thread *td, struct linux_connect_args *args) * socket and use the file descriptor reference instead of * creating a new one. */ - error = fgetsock(td, args->s, CAP_CONNECT, &so, &fflag); + error = fgetsock(td, args->s, cap_rights_init(&rights, CAP_CONNECT), + &so, &fflag); if (error == 0) { error = EISCONN; if (fflag & FNONBLOCK) { diff --git a/sys/compat/svr4/svr4_fcntl.c b/sys/compat/svr4/svr4_fcntl.c index 86fab788efa9..8d0b7156d251 100644 --- a/sys/compat/svr4/svr4_fcntl.c +++ b/sys/compat/svr4/svr4_fcntl.c @@ -259,6 +259,7 @@ fd_revoke(td, fd) struct vnode *vp; struct mount *mp; struct vattr vattr; + cap_rights_t rights; int error, *retval; retval = td->td_retval; @@ -267,12 +268,13 @@ fd_revoke(td, fd) * or FreeBSD grows a native frevoke() (more likely), we will need a * CAP_FREVOKE here. * - * In the meantime, use CAP_ALL: if a SVR4 process wants to + * In the meantime, use CAP_ALL(): if a SVR4 process wants to * do an frevoke(), it needs to do it on either a regular file * descriptor or a fully-privileged capability (which is effectively * the same as a non-capability-restricted file descriptor). */ - if ((error = fgetvp(td, fd, CAP_ALL, &vp)) != 0) + CAP_ALL(&rights); + if ((error = fgetvp(td, fd, &rights, &vp)) != 0) return (error); if (vp->v_type != VCHR && vp->v_type != VBLK) { @@ -318,13 +320,15 @@ fd_truncate(td, fd, flp) struct vattr vattr; int error, *retval; struct ftruncate_args ft; + cap_rights_t rights; retval = td->td_retval; /* * We only support truncating the file. */ - if ((error = fget(td, fd, CAP_FTRUNCATE, &fp)) != 0) + error = fget(td, fd, cap_rights_init(&rights, CAP_FTRUNCATE), &fp); + if (error != 0) return (error); vp = fp->f_vnode; @@ -401,9 +405,11 @@ svr4_sys_open(td, uap) if (!(bsd_flags & O_NOCTTY) && SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) { #if defined(NOTYET) - struct file *fp; + cap_rights_t rights; + struct file *fp; - error = fget(td, retval, CAP_IOCTL, &fp); + error = fget(td, retval, + cap_rights_init(&rights, CAP_IOCTL), &fp); PROC_UNLOCK(p); /* * we may have lost a race the above open() and diff --git a/sys/compat/svr4/svr4_filio.c b/sys/compat/svr4/svr4_filio.c index 0fbba0754a0c..b953e72136f9 100644 --- a/sys/compat/svr4/svr4_filio.c +++ b/sys/compat/svr4/svr4_filio.c @@ -104,6 +104,7 @@ svr4_sys_read(td, uap) struct svr4_sys_read_args *uap; { struct read_args ra; + cap_rights_t rights; struct file *fp; struct socket *so = NULL; int so_state; @@ -114,7 +115,7 @@ svr4_sys_read(td, uap) ra.buf = uap->buf; ra.nbyte = uap->nbyte; - if (fget(td, uap->fd, CAP_READ, &fp) != 0) { + if (fget(td, uap->fd, cap_rights_init(&rights, CAP_READ), &fp) != 0) { DPRINTF(("Something fishy with the user-supplied file descriptor...\n")); return EBADF; } diff --git a/sys/compat/svr4/svr4_ioctl.c b/sys/compat/svr4/svr4_ioctl.c index 36b05803821f..a8c8c8c36243 100644 --- a/sys/compat/svr4/svr4_ioctl.c +++ b/sys/compat/svr4/svr4_ioctl.c @@ -84,6 +84,7 @@ svr4_sys_ioctl(td, uap) struct svr4_sys_ioctl_args *uap; { int *retval; + cap_rights_t rights; struct file *fp; u_long cmd; int (*fun)(struct file *, struct thread *, register_t *, @@ -103,7 +104,8 @@ svr4_sys_ioctl(td, uap) retval = td->td_retval; cmd = uap->com; - if ((error = fget(td, uap->fd, CAP_IOCTL, &fp)) != 0) + error = fget(td, uap->fd, cap_rights_init(&rights, CAP_IOCTL), &fp); + if (error != 0) return (error); if ((fp->f_flag & (FREAD | FWRITE)) == 0) { diff --git a/sys/compat/svr4/svr4_misc.c b/sys/compat/svr4/svr4_misc.c index 0cfaeaebb6cc..48886987b7cb 100644 --- a/sys/compat/svr4/svr4_misc.c +++ b/sys/compat/svr4/svr4_misc.c @@ -236,6 +236,7 @@ svr4_sys_getdents64(td, uap) int len, reclen; /* BSD-format */ caddr_t outp; /* SVR4-format */ int resid, svr4reclen=0; /* SVR4-format */ + cap_rights_t rights; struct file *fp; struct uio auio; struct iovec aiov; @@ -247,7 +248,9 @@ svr4_sys_getdents64(td, uap) DPRINTF(("svr4_sys_getdents64(%d, *, %d)\n", uap->fd, uap->nbytes)); - if ((error = getvnode(td->td_proc->p_fd, uap->fd, CAP_READ, &fp)) != 0) + error = getvnode(td->td_proc->p_fd, uap->fd, + cap_rights_init(&rights, CAP_READ), &fp); + if (error != 0) return (error); if ((fp->f_flag & FREAD) == 0) { @@ -412,6 +415,7 @@ svr4_sys_getdents(td, uap) int len, reclen; /* BSD-format */ caddr_t outp; /* SVR4-format */ int resid, svr4_reclen; /* SVR4-format */ + cap_rights_t rights; struct file *fp; struct uio auio; struct iovec aiov; @@ -424,7 +428,9 @@ svr4_sys_getdents(td, uap) if (uap->nbytes < 0) return (EINVAL); - if ((error = getvnode(td->td_proc->p_fd, uap->fd, CAP_READ, &fp)) != 0) + error = getvnode(td->td_proc->p_fd, uap->fd, + cap_rights_init(&rights, CAP_READ), &fp); + if (error != 0) return (error); if ((fp->f_flag & FREAD) == 0) { diff --git a/sys/compat/svr4/svr4_stream.c b/sys/compat/svr4/svr4_stream.c index 1c7e83edb914..6348b9b51c67 100644 --- a/sys/compat/svr4/svr4_stream.c +++ b/sys/compat/svr4/svr4_stream.c @@ -1446,10 +1446,12 @@ svr4_sys_putmsg(td, uap) struct thread *td; struct svr4_sys_putmsg_args *uap; { - struct file *fp; + cap_rights_t rights; + struct file *fp; int error; - if ((error = fget(td, uap->fd, CAP_SEND, &fp)) != 0) { + error = fget(td, uap->fd, cap_rights_init(&rights, CAP_SEND), &fp); + if (error != 0) { #ifdef DEBUG_SVR4 uprintf("putmsg: bad fp\n"); #endif @@ -1618,10 +1620,12 @@ svr4_sys_getmsg(td, uap) struct thread *td; struct svr4_sys_getmsg_args *uap; { - struct file *fp; + cap_rights_t rights; + struct file *fp; int error; - if ((error = fget(td, uap->fd, CAP_RECV, &fp)) != 0) { + error = fget(td, uap->fd, cap_rights_init(&rights, CAP_RECV), &fp); + if (error != 0) { #ifdef DEBUG_SVR4 uprintf("getmsg: bad fp\n"); #endif diff --git a/sys/conf/files b/sys/conf/files index f02944ff3ac9..8bb4eff524be 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -2847,6 +2847,7 @@ kern/subr_blist.c standard kern/subr_bus.c standard kern/subr_bus_dma.c standard kern/subr_bufring.c standard +kern/subr_capability.c standard kern/subr_clock.c standard kern/subr_counter.c standard kern/subr_devstat.c standard diff --git a/sys/dev/aac/aac_linux.c b/sys/dev/aac/aac_linux.c index 049e2be78e5b..591dfbbdcaa0 100644 --- a/sys/dev/aac/aac_linux.c +++ b/sys/dev/aac/aac_linux.c @@ -75,11 +75,13 @@ MODULE_DEPEND(aac_linux, linux, 1, 1, 1); static int aac_linux_ioctl(struct thread *td, struct linux_ioctl_args *args) { + cap_rights_t rights; struct file *fp; u_long cmd; int error; - if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) + error = fget(td, args->fd, cap_rights_init(&rights, CAP_IOCTL), &fp); + if (error != 0) return (error); cmd = args->cmd; diff --git a/sys/dev/amr/amr_linux.c b/sys/dev/amr/amr_linux.c index 44e858ba804e..5b1a17f530b1 100644 --- a/sys/dev/amr/amr_linux.c +++ b/sys/dev/amr/amr_linux.c @@ -72,10 +72,12 @@ MODULE_DEPEND(amr, linux, 1, 1, 1); static int amr_linux_ioctl(struct thread *p, struct linux_ioctl_args *args) { + cap_rights_t rights; struct file *fp; int error; - if ((error = fget(p, args->fd, CAP_IOCTL, &fp)) != 0) + error = fget(p, args->fd, cap_rights_init(&rights, CAP_IOCTL), &fp); + if (error != 0) return (error); error = fo_ioctl(fp, args->cmd, (caddr_t)args->arg, p->td_ucred, p); fdrop(fp, p); diff --git a/sys/dev/filemon/filemon.c b/sys/dev/filemon/filemon.c index ce84e3df4252..e3fda1829ec0 100644 --- a/sys/dev/filemon/filemon.c +++ b/sys/dev/filemon/filemon.c @@ -138,12 +138,6 @@ filemon_dtr(void *data) } } -#if __FreeBSD_version < 900041 -#define FGET_WRITE(a1, a2, a3) fget_write((a1), (a2), (a3)) -#else -#define FGET_WRITE(a1, a2, a3) fget_write((a1), (a2), CAP_WRITE | CAP_SEEK, (a3)) -#endif - static int filemon_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag __unused, struct thread *td) @@ -151,13 +145,21 @@ filemon_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag __unused, int error = 0; struct filemon *filemon; struct proc *p; +#if __FreeBSD_version >= 900041 + cap_rights_t rights; +#endif devfs_get_cdevpriv((void **) &filemon); switch (cmd) { /* Set the output file descriptor. */ case FILEMON_SET_FD: - if ((error = FGET_WRITE(td, *(int *)data, &filemon->fp)) == 0) + error = fget_write(td, *(int *)data, +#if __FreeBSD_version >= 900041 + cap_rights_init(&rights, CAP_PWRITE), +#endif + &filemon->fp); + if (error == 0) /* Write the file header. */ filemon_comment(filemon); break; diff --git a/sys/dev/hwpmc/hwpmc_logging.c b/sys/dev/hwpmc/hwpmc_logging.c index 880bcaac0a0b..a60e096eed25 100644 --- a/sys/dev/hwpmc/hwpmc_logging.c +++ b/sys/dev/hwpmc/hwpmc_logging.c @@ -570,6 +570,7 @@ pmclog_configure_log(struct pmc_mdep *md, struct pmc_owner *po, int logfd) { int error; struct proc *p; + cap_rights_t rights; /* * As long as it is possible to get a LOR between pmc_sx lock and @@ -593,7 +594,8 @@ pmclog_configure_log(struct pmc_mdep *md, struct pmc_owner *po, int logfd) po->po_file)); /* get a reference to the file state */ - error = fget_write(curthread, logfd, CAP_WRITE, &po->po_file); + error = fget_write(curthread, logfd, + cap_rights_init(&rights, CAP_WRITE), &po->po_file); if (error) goto error; diff --git a/sys/dev/ipmi/ipmi_linux.c b/sys/dev/ipmi/ipmi_linux.c index 430bd0858948..b6b38f22b16a 100644 --- a/sys/dev/ipmi/ipmi_linux.c +++ b/sys/dev/ipmi/ipmi_linux.c @@ -89,11 +89,13 @@ MODULE_DEPEND(ipmi_linux, linux, 1, 1, 1); static int ipmi_linux_ioctl(struct thread *td, struct linux_ioctl_args *args) { + cap_rights_t rights; struct file *fp; u_long cmd; int error; - if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) + error = fget(td, args->fd, cap_rights_init(&rights, CAP_IOCTL), &fp); + if (error != 0) return (error); cmd = args->cmd; diff --git a/sys/dev/iscsi_initiator/iscsi.c b/sys/dev/iscsi_initiator/iscsi.c index 4dbf16349903..4a1cb967ffa0 100644 --- a/sys/dev/iscsi_initiator/iscsi.c +++ b/sys/dev/iscsi_initiator/iscsi.c @@ -382,16 +382,19 @@ i_ping(struct cdev *dev) static int i_setsoc(isc_session_t *sp, int fd, struct thread *td) { + cap_rights_t rights; int error = 0; if(sp->soc != NULL) isc_stop_receiver(sp); - error = fget(td, fd, CAP_SOCK_CLIENT, &sp->fp); + error = fget(td, fd, cap_rights_init(&rights, CAP_SOCK_CLIENT), &sp->fp); if(error) return error; - if((error = fgetsock(td, fd, CAP_SOCK_CLIENT, &sp->soc, 0)) == 0) { + error = fgetsock(td, fd, cap_rights_init(&rights, CAP_SOCK_CLIENT), + &sp->soc, 0); + if(error == 0) { sp->td = td; isc_start_receiver(sp); } diff --git a/sys/dev/mfi/mfi_linux.c b/sys/dev/mfi/mfi_linux.c index 3328a6650cd6..429d49600c07 100644 --- a/sys/dev/mfi/mfi_linux.c +++ b/sys/dev/mfi/mfi_linux.c @@ -84,6 +84,7 @@ MODULE_DEPEND(mfi, linux, 1, 1, 1); static int mfi_linux_ioctl(struct thread *p, struct linux_ioctl_args *args) { + cap_rights_t rights; struct file *fp; int error; u_long cmd = args->cmd; @@ -97,7 +98,8 @@ mfi_linux_ioctl(struct thread *p, struct linux_ioctl_args *args) break; } - if ((error = fget(p, args->fd, CAP_IOCTL, &fp)) != 0) + error = fget(p, args->fd, cap_rights_init(&rights, CAP_IOCTL), &fp); + if (error != 0) return (error); error = fo_ioctl(fp, cmd, (caddr_t)args->arg, p->td_ucred, p); fdrop(fp, p); diff --git a/sys/dev/tdfx/tdfx_linux.c b/sys/dev/tdfx/tdfx_linux.c index 0b769f01a241..fa39ab1903b9 100644 --- a/sys/dev/tdfx/tdfx_linux.c +++ b/sys/dev/tdfx/tdfx_linux.c @@ -45,6 +45,7 @@ LINUX_IOCTL_SET(tdfx, LINUX_IOCTL_TDFX_MIN, LINUX_IOCTL_TDFX_MAX); static int linux_ioctl_tdfx(struct thread *td, struct linux_ioctl_args* args) { + cap_rights_t rights; int error = 0; u_long cmd = args->cmd & 0xffff; @@ -54,7 +55,8 @@ linux_ioctl_tdfx(struct thread *td, struct linux_ioctl_args* args) struct file *fp; - if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) + error = fget(td, args->fd, cap_rights_init(&rights, CAP_IOCTL), &fp); + if (error != 0) return (error); /* We simply copy the data and send it right to ioctl */ copyin((caddr_t)args->arg, &d_pio, sizeof(d_pio)); diff --git a/sys/fs/fdescfs/fdesc_vnops.c b/sys/fs/fdescfs/fdesc_vnops.c index f18c0fc13f95..fe939b1f6577 100644 --- a/sys/fs/fdescfs/fdesc_vnops.c +++ b/sys/fs/fdescfs/fdesc_vnops.c @@ -445,6 +445,7 @@ fdesc_setattr(ap) struct mount *mp; struct file *fp; struct thread *td = curthread; + cap_rights_t rights; unsigned fd; int error; @@ -459,7 +460,8 @@ fdesc_setattr(ap) /* * Allow setattr where there is an underlying vnode. */ - error = getvnode(td->td_proc->p_fd, fd, CAP_EXTATTR_SET, &fp); + error = getvnode(td->td_proc->p_fd, fd, + cap_rights_init(&rights, CAP_EXTATTR_SET), &fp); if (error) { /* * getvnode() returns EINVAL if the file descriptor is not diff --git a/sys/fs/fuse/fuse_vfsops.c b/sys/fs/fuse/fuse_vfsops.c index 639550a88c8d..0b4f19b9ea42 100644 --- a/sys/fs/fuse/fuse_vfsops.c +++ b/sys/fs/fuse/fuse_vfsops.c @@ -220,6 +220,7 @@ fuse_vfsop_mount(struct mount *mp) struct file *fp, *fptmp; char *fspec, *subtype; struct vfsoptlist *opts; + cap_rights_t rights; subtype = NULL; max_read_set = 0; @@ -289,7 +290,7 @@ fuse_vfsop_mount(struct mount *mp) FS_DEBUG2G("mntopts 0x%jx\n", (uintmax_t)mntopts); - err = fget(td, fd, CAP_READ, &fp); + err = fget(td, fd, cap_rights_init(&rights, CAP_READ), &fp); if (err != 0) { FS_DEBUG("invalid or not opened device: data=%p\n", data); goto out; diff --git a/sys/fs/nfsclient/nfs_clport.c b/sys/fs/nfsclient/nfs_clport.c index d7b082b6ae89..b198d5976982 100644 --- a/sys/fs/nfsclient/nfs_clport.c +++ b/sys/fs/nfsclient/nfs_clport.c @@ -1219,10 +1219,11 @@ nfssvc_nfscl(struct thread *td, struct nfssvc_args *uap) struct file *fp; struct nfscbd_args nfscbdarg; struct nfsd_nfscbd_args nfscbdarg2; - int error; struct nameidata nd; struct nfscl_dumpmntopts dumpmntopts; + cap_rights_t rights; char *buf; + int error; if (uap->flag & NFSSVC_CBADDSOCK) { error = copyin(uap->argp, (caddr_t)&nfscbdarg, sizeof(nfscbdarg)); @@ -1233,10 +1234,10 @@ nfssvc_nfscl(struct thread *td, struct nfssvc_args *uap) * pretend that we need them all. It is better to be too * careful than too reckless. */ - if ((error = fget(td, nfscbdarg.sock, CAP_SOCK_CLIENT, &fp)) - != 0) { + error = fget(td, nfscbdarg.sock, + cap_rights_init(&rights, CAP_SOCK_CLIENT), &fp); + if (error) return (error); - } if (fp->f_type != DTYPE_SOCKET) { fdrop(fp, td); return (EPERM); diff --git a/sys/fs/nfsserver/nfs_nfsdport.c b/sys/fs/nfsserver/nfs_nfsdport.c index a6a01692edf0..2f9d40a8f2e3 100644 --- a/sys/fs/nfsserver/nfs_nfsdport.c +++ b/sys/fs/nfsserver/nfs_nfsdport.c @@ -3035,6 +3035,7 @@ nfssvc_nfsd(struct thread *td, struct nfssvc_args *uap) struct file *fp; struct nfsd_addsock_args sockarg; struct nfsd_nfsd_args nfsdarg; + cap_rights_t rights; int error; if (uap->flag & NFSSVC_NFSDADDSOCK) { @@ -3046,7 +3047,9 @@ nfssvc_nfsd(struct thread *td, struct nfssvc_args *uap) * pretend that we need them all. It is better to be too * careful than too reckless. */ - if ((error = fget(td, sockarg.sock, CAP_SOCK_SERVER, &fp)) != 0) + error = fget(td, sockarg.sock, + cap_rights_init(&rights, CAP_SOCK_SERVER), &fp); + if (error != 0) goto out; if (fp->f_type != DTYPE_SOCKET) { fdrop(fp, td); diff --git a/sys/i386/ibcs2/ibcs2_fcntl.c b/sys/i386/ibcs2/ibcs2_fcntl.c index 2902da74bcdf..d061b7968742 100644 --- a/sys/i386/ibcs2/ibcs2_fcntl.c +++ b/sys/i386/ibcs2/ibcs2_fcntl.c @@ -201,10 +201,12 @@ ibcs2_open(td, uap) free(path, M_TEMP); PROC_LOCK(p); if (!ret && !noctty && SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) { + cap_rights_t rights; struct file *fp; int error; - error = fget(td, td->td_retval[0], CAP_IOCTL, &fp); + error = fget(td, td->td_retval[0], + cap_rights_init(&rights, CAP_IOCTL), &fp); PROC_UNLOCK(p); if (error) return (EBADF); diff --git a/sys/i386/ibcs2/ibcs2_ioctl.c b/sys/i386/ibcs2/ibcs2_ioctl.c index 83e68cd45197..03fa5f6218ba 100644 --- a/sys/i386/ibcs2/ibcs2_ioctl.c +++ b/sys/i386/ibcs2/ibcs2_ioctl.c @@ -331,10 +331,12 @@ ibcs2_ioctl(td, uap) struct ibcs2_ioctl_args *uap; { struct proc *p = td->td_proc; + cap_rights_t rights; struct file *fp; int error; - if ((error = fget(td, uap->fd, CAP_IOCTL, &fp)) != 0) { + error = fget(td, uap->fd, cap_rights_init(&rights, CAP_IOCTL), &fp); + if (error != 0) { DPRINTF(("ibcs2_ioctl(%d): bad fd %d ", p->p_pid, uap->fd)); return EBADF; diff --git a/sys/i386/ibcs2/ibcs2_misc.c b/sys/i386/ibcs2/ibcs2_misc.c index 9f382aaf7070..28cd83cbd5a0 100644 --- a/sys/i386/ibcs2/ibcs2_misc.c +++ b/sys/i386/ibcs2/ibcs2_misc.c @@ -326,6 +326,7 @@ ibcs2_getdents(td, uap) register int len, reclen; /* BSD-format */ register caddr_t outp; /* iBCS2-format */ register int resid; /* iBCS2-format */ + cap_rights_t rights; struct file *fp; struct uio auio; struct iovec aiov; @@ -337,7 +338,9 @@ ibcs2_getdents(td, uap) #define BSD_DIRENT(cp) ((struct dirent *)(cp)) #define IBCS2_RECLEN(reclen) (reclen + sizeof(u_short)) - if ((error = getvnode(td->td_proc->p_fd, uap->fd, CAP_READ, &fp)) != 0) + error = getvnode(td->td_proc->p_fd, uap->fd, + cap_rights_init(&rights, CAP_READ), &fp); + if (error != 0) return (error); if ((fp->f_flag & FREAD) == 0) { fdrop(fp, td); @@ -478,6 +481,7 @@ ibcs2_read(td, uap) register int len, reclen; /* BSD-format */ register caddr_t outp; /* iBCS2-format */ register int resid; /* iBCS2-format */ + cap_rights_t rights; struct file *fp; struct uio auio; struct iovec aiov; @@ -490,8 +494,9 @@ ibcs2_read(td, uap) u_long *cookies = NULL, *cookiep; int ncookies; - if ((error = getvnode(td->td_proc->p_fd, uap->fd, CAP_READ, - &fp)) != 0) { + error = getvnode(td->td_proc->p_fd, uap->fd, + cap_rights_init(&rights, CAP_READ), &fp); + if (error != 0) { if (error == EINVAL) return sys_read(td, (struct read_args *)uap); else diff --git a/sys/i386/linux/linux_machdep.c b/sys/i386/linux/linux_machdep.c index 14d18920b61e..2d792046eb3d 100644 --- a/sys/i386/linux/linux_machdep.c +++ b/sys/i386/linux/linux_machdep.c @@ -422,6 +422,7 @@ linux_mmap_common(struct thread *td, l_uintptr_t addr, l_size_t len, l_int prot, } */ bsd_args; int error; struct file *fp; + cap_rights_t rights; error = 0; bsd_args.flags = 0; @@ -473,7 +474,9 @@ linux_mmap_common(struct thread *td, l_uintptr_t addr, l_size_t len, l_int prot, * is done in the FreeBSD mmap(). */ - if ((error = fget(td, bsd_args.fd, CAP_MMAP, &fp)) != 0) + error = fget(td, bsd_args.fd, + cap_rights_init(&rights, CAP_MMAP), &fp); + if (error != 0) return (error); if (fp->f_type != DTYPE_VNODE) { fdrop(fp, td); diff --git a/sys/kern/capabilities.conf b/sys/kern/capabilities.conf index d2fa51c4ef84..eaa5b14b47be 100644 --- a/sys/kern/capabilities.conf +++ b/sys/kern/capabilities.conf @@ -114,8 +114,7 @@ cap_fcntls_limit cap_getmode cap_ioctls_get cap_ioctls_limit -cap_new -cap_rights_get +__cap_rights_get cap_rights_limit ## diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c index d0de6b99b8be..a0545e10b1e9 100644 --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -455,6 +455,7 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) struct filedescent *fde; struct proc *p; struct vnode *vp; + cap_rights_t rights; int error, flg, tmp; u_int old, new; uint64_t bsize; @@ -515,7 +516,8 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) break; case F_GETFL: - error = fget_unlocked(fdp, fd, CAP_FCNTL, F_GETFL, &fp, NULL); + error = fget_unlocked(fdp, fd, + cap_rights_init(&rights, CAP_FCNTL), F_GETFL, &fp, NULL); if (error != 0) break; td->td_retval[0] = OFLAGS(fp->f_flag); @@ -523,7 +525,8 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) break; case F_SETFL: - error = fget_unlocked(fdp, fd, CAP_FCNTL, F_SETFL, &fp, NULL); + error = fget_unlocked(fdp, fd, + cap_rights_init(&rights, CAP_FCNTL), F_SETFL, &fp, NULL); if (error != 0) break; do { @@ -550,7 +553,8 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) break; case F_GETOWN: - error = fget_unlocked(fdp, fd, CAP_FCNTL, F_GETOWN, &fp, NULL); + error = fget_unlocked(fdp, fd, + cap_rights_init(&rights, CAP_FCNTL), F_GETOWN, &fp, NULL); if (error != 0) break; error = fo_ioctl(fp, FIOGETOWN, &tmp, td->td_ucred, td); @@ -560,7 +564,8 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) break; case F_SETOWN: - error = fget_unlocked(fdp, fd, CAP_FCNTL, F_SETOWN, &fp, NULL); + error = fget_unlocked(fdp, fd, + cap_rights_init(&rights, CAP_FCNTL), F_SETOWN, &fp, NULL); if (error != 0) break; tmp = arg; @@ -581,7 +586,8 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) case F_SETLK: do_setlk: - error = fget_unlocked(fdp, fd, CAP_FLOCK, 0, &fp, NULL); + error = fget_unlocked(fdp, fd, + cap_rights_init(&rights, CAP_FLOCK), 0, &fp, NULL); if (error != 0) break; if (fp->f_type != DTYPE_VNODE) { @@ -688,7 +694,8 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) break; case F_GETLK: - error = fget_unlocked(fdp, fd, CAP_FLOCK, 0, &fp, NULL); + error = fget_unlocked(fdp, fd, + cap_rights_init(&rights, CAP_FLOCK), 0, &fp, NULL); if (error != 0) break; if (fp->f_type != DTYPE_VNODE) { @@ -1281,11 +1288,13 @@ int kern_fstat(struct thread *td, int fd, struct stat *sbp) { struct file *fp; + cap_rights_t rights; int error; AUDIT_ARG_FD(fd); - if ((error = fget(td, fd, CAP_FSTAT, &fp)) != 0) + error = fget(td, fd, cap_rights_init(&rights, CAP_FSTAT), &fp); + if (error != 0) return (error); AUDIT_ARG_FILE(td->td_proc, fp); @@ -1339,9 +1348,11 @@ sys_fpathconf(struct thread *td, struct fpathconf_args *uap) { struct file *fp; struct vnode *vp; + cap_rights_t rights; int error; - if ((error = fget(td, uap->fd, CAP_FPATHCONF, &fp)) != 0) + error = fget(td, uap->fd, cap_rights_init(&rights, CAP_FPATHCONF), &fp); + if (error != 0) return (error); /* If asynchronous I/O is available, it works for all descriptors. */ @@ -1417,7 +1428,7 @@ static void filecaps_fill(struct filecaps *fcaps) { - fcaps->fc_rights = CAP_ALL; + CAP_ALL(&fcaps->fc_rights); fcaps->fc_ioctls = NULL; fcaps->fc_nioctls = -1; fcaps->fc_fcntls = CAP_FCNTL_ALL; @@ -1441,16 +1452,18 @@ static void filecaps_validate(const struct filecaps *fcaps, const char *func) { - KASSERT((fcaps->fc_rights & ~CAP_MASK_VALID) == 0, + KASSERT(cap_rights_is_valid(&fcaps->fc_rights), ("%s: invalid rights", func)); KASSERT((fcaps->fc_fcntls & ~CAP_FCNTL_ALL) == 0, ("%s: invalid fcntls", func)); - KASSERT(fcaps->fc_fcntls == 0 || (fcaps->fc_rights & CAP_FCNTL) != 0, + KASSERT(fcaps->fc_fcntls == 0 || + cap_rights_is_set(&fcaps->fc_rights, CAP_FCNTL), ("%s: fcntls without CAP_FCNTL", func)); KASSERT(fcaps->fc_ioctls != NULL ? fcaps->fc_nioctls > 0 : (fcaps->fc_nioctls == -1 || fcaps->fc_nioctls == 0), ("%s: invalid ioctls", func)); - KASSERT(fcaps->fc_nioctls == 0 || (fcaps->fc_rights & CAP_IOCTL) != 0, + KASSERT(fcaps->fc_nioctls == 0 || + cap_rights_is_set(&fcaps->fc_rights, CAP_IOCTL), ("%s: ioctls without CAP_IOCTL", func)); } @@ -2285,7 +2298,7 @@ finit(struct file *fp, u_int flag, short type, void *data, struct fileops *ops) } int -fget_unlocked(struct filedesc *fdp, int fd, cap_rights_t needrights, +fget_unlocked(struct filedesc *fdp, int fd, cap_rights_t *needrightsp, int needfcntl, struct file **fpp, cap_rights_t *haverightsp) { struct file *fp; @@ -2310,11 +2323,11 @@ fget_unlocked(struct filedesc *fdp, int fd, cap_rights_t needrights, if (fp == NULL) return (EBADF); #ifdef CAPABILITIES - haverights = cap_rights(fdp, fd); - error = cap_check(haverights, needrights); + haverights = *cap_rights(fdp, fd); + error = cap_check(&haverights, needrightsp); if (error != 0) return (error); - if ((needrights & CAP_FCNTL) != 0) { + if (cap_rights_is_set(needrightsp, CAP_FCNTL)) { error = cap_fcntl_check(fdp, fd, needfcntl); if (error != 0) return (error); @@ -2338,7 +2351,7 @@ fget_unlocked(struct filedesc *fdp, int fd, cap_rights_t needrights, #ifdef CAPABILITIES *haverightsp = haverights; #else - *haverightsp = CAP_ALL; + CAP_ALL(haverightsp); #endif } return (0); @@ -2359,19 +2372,20 @@ fget_unlocked(struct filedesc *fdp, int fd, cap_rights_t needrights, */ static __inline int _fget(struct thread *td, int fd, struct file **fpp, int flags, - cap_rights_t needrights, u_char *maxprotp) + cap_rights_t *needrightsp, u_char *maxprotp) { struct filedesc *fdp; struct file *fp; - cap_rights_t haverights; + cap_rights_t haverights, needrights; int error; *fpp = NULL; if (td == NULL || (fdp = td->td_proc->p_fd) == NULL) return (EBADF); + needrights = *needrightsp; if (maxprotp != NULL) - needrights |= CAP_MMAP; - error = fget_unlocked(fdp, fd, needrights, 0, &fp, &haverights); + cap_rights_set(&needrights, CAP_MMAP); + error = fget_unlocked(fdp, fd, &needrights, 0, &fp, &haverights); if (error != 0) return (error); if (fp->f_ops == &badfileops) { @@ -2384,7 +2398,7 @@ _fget(struct thread *td, int fd, struct file **fpp, int flags, * If requested, convert capability rights to access flags. */ if (maxprotp != NULL) - *maxprotp = cap_rights_to_vmprot(haverights); + *maxprotp = cap_rights_to_vmprot(&haverights); #else /* !CAPABILITIES */ if (maxprotp != NULL) *maxprotp = VM_PROT_ALL; @@ -2421,32 +2435,32 @@ _fget(struct thread *td, int fd, struct file **fpp, int flags, } int -fget(struct thread *td, int fd, cap_rights_t rights, struct file **fpp) +fget(struct thread *td, int fd, cap_rights_t *rightsp, struct file **fpp) { - return(_fget(td, fd, fpp, 0, rights, NULL)); + return(_fget(td, fd, fpp, 0, rightsp, NULL)); } int -fget_mmap(struct thread *td, int fd, cap_rights_t rights, u_char *maxprotp, +fget_mmap(struct thread *td, int fd, cap_rights_t *rightsp, u_char *maxprotp, struct file **fpp) { - return (_fget(td, fd, fpp, 0, rights, maxprotp)); + return (_fget(td, fd, fpp, 0, rightsp, maxprotp)); } int -fget_read(struct thread *td, int fd, cap_rights_t rights, struct file **fpp) +fget_read(struct thread *td, int fd, cap_rights_t *rightsp, struct file **fpp) { - return(_fget(td, fd, fpp, FREAD, rights, NULL)); + return(_fget(td, fd, fpp, FREAD, rightsp, NULL)); } int -fget_write(struct thread *td, int fd, cap_rights_t rights, struct file **fpp) +fget_write(struct thread *td, int fd, cap_rights_t *rightsp, struct file **fpp) { - return (_fget(td, fd, fpp, FWRITE, rights, NULL)); + return (_fget(td, fd, fpp, FWRITE, rightsp, NULL)); } /* @@ -2457,15 +2471,15 @@ fget_write(struct thread *td, int fd, cap_rights_t rights, struct file **fpp) * XXX: what about the unused flags ? */ static __inline int -_fgetvp(struct thread *td, int fd, int flags, cap_rights_t needrights, +_fgetvp(struct thread *td, int fd, int flags, cap_rights_t *needrightsp, struct vnode **vpp) { struct file *fp; int error; *vpp = NULL; - error = _fget(td, fd, &fp, flags, needrights, NULL); - if (error) + error = _fget(td, fd, &fp, flags, needrightsp, NULL); + if (error != 0) return (error); if (fp->f_vnode == NULL) { error = EINVAL; @@ -2479,14 +2493,14 @@ _fgetvp(struct thread *td, int fd, int flags, cap_rights_t needrights, } int -fgetvp(struct thread *td, int fd, cap_rights_t rights, struct vnode **vpp) +fgetvp(struct thread *td, int fd, cap_rights_t *rightsp, struct vnode **vpp) { - return (_fgetvp(td, fd, 0, rights, vpp)); + return (_fgetvp(td, fd, 0, rightsp, vpp)); } int -fgetvp_rights(struct thread *td, int fd, cap_rights_t need, +fgetvp_rights(struct thread *td, int fd, cap_rights_t *needrightsp, struct filecaps *havecaps, struct vnode **vpp) { struct filedesc *fdp; @@ -2503,7 +2517,7 @@ fgetvp_rights(struct thread *td, int fd, cap_rights_t need, return (EBADF); #ifdef CAPABILITIES - error = cap_check(cap_rights(fdp, fd), need); + error = cap_check(cap_rights(fdp, fd), needrightsp); if (error != 0) return (error); #endif @@ -2519,26 +2533,26 @@ fgetvp_rights(struct thread *td, int fd, cap_rights_t need, } int -fgetvp_read(struct thread *td, int fd, cap_rights_t rights, struct vnode **vpp) +fgetvp_read(struct thread *td, int fd, cap_rights_t *rightsp, struct vnode **vpp) { - return (_fgetvp(td, fd, FREAD, rights, vpp)); + return (_fgetvp(td, fd, FREAD, rightsp, vpp)); } int -fgetvp_exec(struct thread *td, int fd, cap_rights_t rights, struct vnode **vpp) +fgetvp_exec(struct thread *td, int fd, cap_rights_t *rightsp, struct vnode **vpp) { - return (_fgetvp(td, fd, FEXEC, rights, vpp)); + return (_fgetvp(td, fd, FEXEC, rightsp, vpp)); } #ifdef notyet int -fgetvp_write(struct thread *td, int fd, cap_rights_t rights, +fgetvp_write(struct thread *td, int fd, cap_rights_t *rightsp, struct vnode **vpp) { - return (_fgetvp(td, fd, FWRITE, rights, vpp)); + return (_fgetvp(td, fd, FWRITE, rightsp, vpp)); } #endif @@ -2554,7 +2568,7 @@ fgetvp_write(struct thread *td, int fd, cap_rights_t rights, * during use. */ int -fgetsock(struct thread *td, int fd, cap_rights_t rights, struct socket **spp, +fgetsock(struct thread *td, int fd, cap_rights_t *rightsp, struct socket **spp, u_int *fflagp) { struct file *fp; @@ -2563,7 +2577,7 @@ fgetsock(struct thread *td, int fd, cap_rights_t rights, struct socket **spp, *spp = NULL; if (fflagp != NULL) *fflagp = 0; - if ((error = _fget(td, fd, &fp, 0, rights, NULL)) != 0) + if ((error = _fget(td, fd, &fp, 0, rightsp, NULL)) != 0) return (error); if (fp->f_type != DTYPE_SOCKET) { error = ENOTSOCK; @@ -2637,9 +2651,11 @@ sys_flock(struct thread *td, struct flock_args *uap) struct file *fp; struct vnode *vp; struct flock lf; + cap_rights_t rights; int error; - if ((error = fget(td, uap->fd, CAP_FLOCK, &fp)) != 0) + error = fget(td, uap->fd, cap_rights_init(&rights, CAP_FLOCK), &fp); + if (error != 0) return (error); if (fp->f_type != DTYPE_VNODE) { fdrop(fp, td); @@ -3185,7 +3201,7 @@ struct export_fd_buf { static int export_fd_to_sb(void *data, int type, int fd, int fflags, int refcnt, - int64_t offset, cap_rights_t fd_cap_rights, struct export_fd_buf *efbuf) + int64_t offset, cap_rights_t *rightsp, struct export_fd_buf *efbuf) { struct { int fflag; @@ -3259,7 +3275,10 @@ export_fd_to_sb(void *data, int type, int fd, int fflags, int refcnt, for (i = 0; i < NFFLAGS; i++) if (fflags & fflags_table[i].fflag) kif->kf_flags |= fflags_table[i].kf_fflag; - kif->kf_cap_rights = fd_cap_rights; + if (rightsp != NULL) + kif->kf_cap_rights = *rightsp; + else + cap_rights_init(&kif->kf_cap_rights); kif->kf_fd = fd; kif->kf_type = type; kif->kf_ref_count = refcnt; @@ -3302,7 +3321,7 @@ kern_proc_filedesc_out(struct proc *p, struct sbuf *sb, ssize_t maxlen) void *data; int error, i; int type, refcnt, fflags; - cap_rights_t fd_cap_rights; + cap_rights_t rights; PROC_LOCK_ASSERT(p, MA_OWNED); @@ -3329,13 +3348,13 @@ kern_proc_filedesc_out(struct proc *p, struct sbuf *sb, ssize_t maxlen) efbuf->remainder = maxlen; if (tracevp != NULL) export_fd_to_sb(tracevp, KF_TYPE_VNODE, KF_FD_TYPE_TRACE, - FREAD | FWRITE, -1, -1, 0, efbuf); + FREAD | FWRITE, -1, -1, NULL, efbuf); if (textvp != NULL) export_fd_to_sb(textvp, KF_TYPE_VNODE, KF_FD_TYPE_TEXT, - FREAD, -1, -1, 0, efbuf); + FREAD, -1, -1, NULL, efbuf); if (cttyvp != NULL) export_fd_to_sb(cttyvp, KF_TYPE_VNODE, KF_FD_TYPE_CTTY, - FREAD | FWRITE, -1, -1, 0, efbuf); + FREAD | FWRITE, -1, -1, NULL, efbuf); error = 0; if (fdp == NULL) goto fail; @@ -3346,30 +3365,30 @@ kern_proc_filedesc_out(struct proc *p, struct sbuf *sb, ssize_t maxlen) vref(fdp->fd_cdir); data = fdp->fd_cdir; export_fd_to_sb(data, KF_TYPE_VNODE, KF_FD_TYPE_CWD, - FREAD, -1, -1, 0, efbuf); + FREAD, -1, -1, NULL, efbuf); } /* root directory */ if (fdp->fd_rdir != NULL) { vref(fdp->fd_rdir); data = fdp->fd_rdir; export_fd_to_sb(data, KF_TYPE_VNODE, KF_FD_TYPE_ROOT, - FREAD, -1, -1, 0, efbuf); + FREAD, -1, -1, NULL, efbuf); } /* jail directory */ if (fdp->fd_jdir != NULL) { vref(fdp->fd_jdir); data = fdp->fd_jdir; export_fd_to_sb(data, KF_TYPE_VNODE, KF_FD_TYPE_JAIL, - FREAD, -1, -1, 0, efbuf); + FREAD, -1, -1, NULL, efbuf); } for (i = 0; i < fdp->fd_nfiles; i++) { if ((fp = fdp->fd_ofiles[i].fde_file) == NULL) continue; data = NULL; #ifdef CAPABILITIES - fd_cap_rights = cap_rights(fdp, i); + rights = *cap_rights(fdp, i); #else /* !CAPABILITIES */ - fd_cap_rights = 0; + cap_rights_init(&rights); #endif switch (fp->f_type) { case DTYPE_VNODE: @@ -3443,8 +3462,8 @@ kern_proc_filedesc_out(struct proc *p, struct sbuf *sb, ssize_t maxlen) * the loop continues. */ error = export_fd_to_sb(data, type, i, fflags, refcnt, - offset, fd_cap_rights, efbuf); - if (error) + offset, &rights, efbuf); + if (error != 0) break; } FILEDESC_SUNLOCK(fdp); diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c index dfd1c46d625e..8bde25a3e155 100644 --- a/sys/kern/kern_event.c +++ b/sys/kern/kern_event.c @@ -824,9 +824,11 @@ kern_kevent(struct thread *td, int fd, int nchanges, int nevents, struct kevent *kevp, *changes; struct kqueue *kq; struct file *fp; + cap_rights_t rights; int i, n, nerrors, error; - if ((error = fget(td, fd, CAP_POST_EVENT, &fp)) != 0) + error = fget(td, fd, cap_rights_init(&rights, CAP_POST_EVENT), &fp); + if (error != 0) return (error); if ((error = kqueue_acquire(fp, &kq)) != 0) goto done_norel; @@ -964,6 +966,7 @@ kqueue_register(struct kqueue *kq, struct kevent *kev, struct thread *td, int wa struct filterops *fops; struct file *fp; struct knote *kn, *tkn; + cap_rights_t rights; int error, filt, event; int haskqglobal; @@ -982,7 +985,8 @@ kqueue_register(struct kqueue *kq, struct kevent *kev, struct thread *td, int wa findkn: if (fops->f_isfd) { KASSERT(td != NULL, ("td is NULL")); - error = fget(td, kev->ident, CAP_POLL_EVENT, &fp); + error = fget(td, kev->ident, + cap_rights_init(&rights, CAP_POLL_EVENT), &fp); if (error) goto done; @@ -2237,9 +2241,11 @@ kqfd_register(int fd, struct kevent *kev, struct thread *td, int waitok) { struct kqueue *kq; struct file *fp; + cap_rights_t rights; int error; - if ((error = fget(td, fd, CAP_POST_EVENT, &fp)) != 0) + error = fget(td, fd, cap_rights_init(&rights, CAP_POST_EVENT), &fp); + if (error != 0) return (error); if ((error = kqueue_acquire(fp, &kq)) != 0) goto noacquire; diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c index 833fd18ae790..45f732b2f85d 100644 --- a/sys/kern/kern_exec.c +++ b/sys/kern/kern_exec.c @@ -338,6 +338,7 @@ do_execve(td, args, mac_p) struct ucred *tracecred = NULL; #endif struct vnode *textvp = NULL, *binvp = NULL; + cap_rights_t rights; int credential_changing; int textset; #ifdef MAC @@ -438,7 +439,8 @@ interpret: /* * Descriptors opened only with O_EXEC or O_RDONLY are allowed. */ - error = fgetvp_exec(td, args->fd, CAP_FEXECVE, &binvp); + error = fgetvp_exec(td, args->fd, + cap_rights_init(&rights, CAP_FEXECVE), &binvp); if (error) goto exec_fail; vn_lock(binvp, LK_EXCLUSIVE | LK_RETRY); diff --git a/sys/kern/kern_ktrace.c b/sys/kern/kern_ktrace.c index e512a33b2c9c..3b34fb0d8ee9 100644 --- a/sys/kern/kern_ktrace.c +++ b/sys/kern/kern_ktrace.c @@ -779,8 +779,8 @@ ktrstruct(name, data, datalen) void ktrcapfail(type, needed, held) enum ktr_cap_fail_type type; - cap_rights_t needed; - cap_rights_t held; + const cap_rights_t *needed; + const cap_rights_t *held; { struct thread *td = curthread; struct ktr_request *req; @@ -791,8 +791,8 @@ ktrcapfail(type, needed, held) return; kcf = &req->ktr_data.ktr_cap_fail; kcf->cap_type = type; - kcf->cap_needed = needed; - kcf->cap_held = held; + kcf->cap_needed = *needed; + kcf->cap_held = *held; ktr_enqueuerequest(td, req); ktrace_exit(td); } diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index 22fc1b78bac5..1797ebc7dd43 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -1726,6 +1726,7 @@ sys_pdkill(td, uap) { #ifdef PROCDESC struct proc *p; + cap_rights_t rights; int error; AUDIT_ARG_SIGNUM(uap->signum); @@ -1733,7 +1734,8 @@ sys_pdkill(td, uap) if ((u_int)uap->signum > _SIG_MAXSIG) return (EINVAL); - error = procdesc_find(td, uap->fd, CAP_PDKILL, &p); + error = procdesc_find(td, uap->fd, + cap_rights_init(&rights, CAP_PDKILL), &p); if (error) return (error); AUDIT_ARG_PROCESS(p); diff --git a/sys/kern/subr_capability.c b/sys/kern/subr_capability.c new file mode 100644 index 000000000000..7043fe7ae470 --- /dev/null +++ b/sys/kern/subr_capability.c @@ -0,0 +1,285 @@ +/*- + * Copyright (c) 2013 FreeBSD Foundation + * All rights reserved. + * + * This software was developed by Pawel Jakub Dawidek under sponsorship from + * the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#ifdef _KERNEL +#include +#include +#include + +#include +#else /* !_KERNEL */ +#include +#include + +#include +#include +#include +#include +#include +#endif + +#ifdef _KERNEL +#define assert(exp) KASSERT((exp), ("%s:%u", __func__, __LINE__)) +#endif + +static __inline unsigned int +right_to_index(uint64_t right) +{ + static const int bit2idx[] = { + -1, 0, 1, -1, 2, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1, + 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 + }; + int idx; + + idx = CAPIDXBIT(right); + assert(idx == 1 || idx == 2 || idx == 4 || idx == 8 || idx == 16); + + idx = bit2idx[idx]; + assert(idx >= 0 && idx <= 4); + + return ((unsigned int)idx); +} + +static void +cap_rights_vset(cap_rights_t *rights, va_list ap) +{ + unsigned int i, n; + uint64_t right; + + assert(CAPVER(rights) == CAP_RIGHTS_VERSION_00); + + n = CAPARSIZE(rights); + + for (;;) { + right = (uint64_t)va_arg(ap, unsigned long long); + if (right == 0) + break; + assert(CAPRVER(right) == 0); + i = right_to_index(right); + assert(i < n); + assert(CAPIDXBIT(rights->cr_rights[i]) == CAPIDXBIT(right)); + rights->cr_rights[i] |= right; + assert(CAPIDXBIT(rights->cr_rights[i]) == CAPIDXBIT(right)); + } +} + +static void +cap_rights_vclear(cap_rights_t *rights, va_list ap) +{ + unsigned int i, n; + uint64_t right; + + assert(CAPVER(rights) == CAP_RIGHTS_VERSION_00); + + n = CAPARSIZE(rights); + + for (;;) { + right = (uint64_t)va_arg(ap, unsigned long long); + if (right == 0) + break; + assert(CAPRVER(right) == 0); + i = right_to_index(right); + assert(i < n); + assert(CAPIDXBIT(rights->cr_rights[i]) == CAPIDXBIT(right)); + rights->cr_rights[i] &= ~(right & 0x01FFFFFFFFFFFFFFULL); + assert(CAPIDXBIT(rights->cr_rights[i]) == CAPIDXBIT(right)); + } +} + +static bool +cap_rights_is_vset(const cap_rights_t *rights, va_list ap) +{ + unsigned int i, n; + uint64_t right; + + assert(CAPVER(rights) == CAP_RIGHTS_VERSION_00); + + n = CAPARSIZE(rights); + + for (;;) { + right = (uint64_t)va_arg(ap, unsigned long long); + if (right == 0) + break; + assert(CAPRVER(right) == 0); + i = right_to_index(right); + assert(i < n); + assert(CAPIDXBIT(rights->cr_rights[i]) == CAPIDXBIT(right)); + if ((rights->cr_rights[i] & right) != right) + return (false); + } + + return (true); +} + +cap_rights_t * +__cap_rights_init(int version, cap_rights_t *rights, ...) +{ + unsigned int n; + va_list ap; + + assert(version == CAP_RIGHTS_VERSION_00); + + n = version + 2; + memset(rights->cr_rights, 0, sizeof(rights->cr_rights[0]) * n); + CAP_NONE(rights); + va_start(ap, rights); + cap_rights_vset(rights, ap); + va_end(ap); + + return (rights); +} + +void +__cap_rights_set(cap_rights_t *rights, ...) +{ + va_list ap; + + assert(CAPVER(rights) == CAP_RIGHTS_VERSION_00); + + va_start(ap, rights); + cap_rights_vset(rights, ap); + va_end(ap); +} + +void +__cap_rights_clear(cap_rights_t *rights, ...) +{ + va_list ap; + + assert(CAPVER(rights) == CAP_RIGHTS_VERSION_00); + + va_start(ap, rights); + cap_rights_vclear(rights, ap); + va_end(ap); +} + +bool +__cap_rights_is_set(const cap_rights_t *rights, ...) +{ + va_list ap; + bool ret; + + assert(CAPVER(rights) == CAP_RIGHTS_VERSION_00); + + va_start(ap, rights); + ret = cap_rights_is_vset(rights, ap); + va_end(ap); + + return (ret); +} + +bool +cap_rights_is_valid(const cap_rights_t *rights) +{ + cap_rights_t allrights; + unsigned int i, j; + + if (CAPVER(rights) != CAP_RIGHTS_VERSION_00) + return (false); + CAP_ALL(&allrights); + if (!cap_rights_contains(&allrights, rights)) + return (false); + for (i = 0; i < CAPARSIZE(rights); i++) { + j = right_to_index(rights->cr_rights[i]); + if (i != j) + return (false); + if (i > 0) { + if (CAPRVER(rights->cr_rights[i]) != 0) + return (false); + } + } + + return (true); +} + +void +cap_rights_merge(cap_rights_t *dst, const cap_rights_t *src) +{ + unsigned int i, n; + + assert(CAPVER(dst) == CAP_RIGHTS_VERSION_00); + assert(CAPVER(src) == CAP_RIGHTS_VERSION_00); + assert(CAPVER(dst) == CAPVER(src)); + assert(cap_rights_is_valid(src)); + assert(cap_rights_is_valid(dst)); + + n = CAPARSIZE(dst); + + for (i = 0; i < n; i++) + dst->cr_rights[i] |= src->cr_rights[i]; + + assert(cap_rights_is_valid(src)); + assert(cap_rights_is_valid(dst)); +} + +void +cap_rights_remove(cap_rights_t *dst, const cap_rights_t *src) +{ + unsigned int i, n; + + assert(CAPVER(dst) == CAP_RIGHTS_VERSION_00); + assert(CAPVER(src) == CAP_RIGHTS_VERSION_00); + assert(CAPVER(dst) == CAPVER(src)); + assert(cap_rights_is_valid(src)); + assert(cap_rights_is_valid(dst)); + + n = CAPARSIZE(dst); + + for (i = 0; i < n; i++) { + dst->cr_rights[i] &= + ~(src->cr_rights[i] & 0x01FFFFFFFFFFFFFFULL); + } + + assert(cap_rights_is_valid(src)); + assert(cap_rights_is_valid(dst)); +} + +bool +cap_rights_contains(const cap_rights_t *big, const cap_rights_t *little) +{ + unsigned int i, n; + + assert(CAPVER(big) == CAP_RIGHTS_VERSION_00); + assert(CAPVER(little) == CAP_RIGHTS_VERSION_00); + assert(CAPVER(big) == CAPVER(little)); + + n = CAPARSIZE(big); + + for (i = 0; i < n; i++) { + if ((big->cr_rights[i] & little->cr_rights[i]) != + little->cr_rights[i]) { + return (false); + } + } + + return (true); +} diff --git a/sys/kern/sys_capability.c b/sys/kern/sys_capability.c index 224042ead5a3..456f7ac7e08c 100644 --- a/sys/kern/sys_capability.c +++ b/sys/kern/sys_capability.c @@ -148,16 +148,19 @@ FEATURE(security_capabilities, "Capsicum Capabilities"); MALLOC_DECLARE(M_FILECAPS); static inline int -_cap_check(cap_rights_t have, cap_rights_t need, enum ktr_cap_fail_type type) +_cap_check(const cap_rights_t *havep, const cap_rights_t *needp, + enum ktr_cap_fail_type type) { + int i; - - if ((need & ~have) != 0) { + for (i = 0; i < nitems(havep->cr_rights); i++) { + if (!cap_rights_contains(havep, needp)) { #ifdef KTRACE - if (KTRPOINT(curthread, KTR_CAPFAIL)) - ktrcapfail(type, need, have); + if (KTRPOINT(curthread, KTR_CAPFAIL)) + ktrcapfail(type, needp, havep); #endif - return (ENOTCAPABLE); + return (ENOTCAPABLE); + } } return (0); } @@ -166,26 +169,26 @@ _cap_check(cap_rights_t have, cap_rights_t need, enum ktr_cap_fail_type type) * Test whether a capability grants the requested rights. */ int -cap_check(cap_rights_t have, cap_rights_t need) +cap_check(const cap_rights_t *havep, const cap_rights_t *needp) { - return (_cap_check(have, need, CAPFAIL_NOTCAPABLE)); + return (_cap_check(havep, needp, CAPFAIL_NOTCAPABLE)); } /* * Convert capability rights into VM access flags. */ u_char -cap_rights_to_vmprot(cap_rights_t have) +cap_rights_to_vmprot(cap_rights_t *havep) { u_char maxprot; maxprot = VM_PROT_NONE; - if (have & CAP_MMAP_R) + if (cap_rights_is_set(havep, CAP_MMAP_R)) maxprot |= VM_PROT_READ; - if (have & CAP_MMAP_W) + if (cap_rights_is_set(havep, CAP_MMAP_W)) maxprot |= VM_PROT_WRITE; - if (have & CAP_MMAP_X) + if (cap_rights_is_set(havep, CAP_MMAP_X)) maxprot |= VM_PROT_EXECUTE; return (maxprot); @@ -196,11 +199,11 @@ cap_rights_to_vmprot(cap_rights_t have) * any other way, as we want to keep all capability permission evaluation in * this one file. */ -cap_rights_t +cap_rights_t * cap_rights(struct filedesc *fdp, int fd) { - return (fdp->fd_ofiles[fd].fde_rights); + return (&fdp->fd_ofiles[fd].fde_rights); } /* @@ -211,32 +214,57 @@ sys_cap_rights_limit(struct thread *td, struct cap_rights_limit_args *uap) { struct filedesc *fdp; cap_rights_t rights; - int error, fd; + int error, fd, version; - fd = uap->fd; - rights = uap->rights; + cap_rights_init(&rights); - AUDIT_ARG_FD(fd); - AUDIT_ARG_RIGHTS(rights); + error = copyin(uap->rightsp, &rights, sizeof(rights.cr_rights[0])); + if (error != 0) + return (error); + version = CAPVER(&rights); + if (version != CAP_RIGHTS_VERSION_00) + return (EINVAL); - if ((rights & ~CAP_ALL) != 0) + error = copyin(uap->rightsp, &rights, + sizeof(rights.cr_rights[0]) * CAPARSIZE(&rights)); + if (error != 0) + return (error); + /* Check for race. */ + if (CAPVER(&rights) != version) return (EINVAL); + if (!cap_rights_is_valid(&rights)) + return (EINVAL); + + if (version != CAP_RIGHTS_VERSION) { + rights.cr_rights[0] &= ~(0x3ULL << 62); + rights.cr_rights[0] |= ((uint64_t)CAP_RIGHTS_VERSION << 62); + } +#ifdef KTRACE + if (KTRPOINT(td, KTR_STRUCT)) + ktrcaprights(&rights); +#endif + + fd = uap->fd; + + AUDIT_ARG_FD(fd); + AUDIT_ARG_RIGHTS(&rights); + fdp = td->td_proc->p_fd; FILEDESC_XLOCK(fdp); if (fget_locked(fdp, fd) == NULL) { FILEDESC_XUNLOCK(fdp); return (EBADF); } - error = _cap_check(cap_rights(fdp, fd), rights, CAPFAIL_INCREASE); + error = _cap_check(cap_rights(fdp, fd), &rights, CAPFAIL_INCREASE); if (error == 0) { fdp->fd_ofiles[fd].fde_rights = rights; - if ((rights & CAP_IOCTL) == 0) { + if (!cap_rights_is_set(&rights, CAP_IOCTL)) { free(fdp->fd_ofiles[fd].fde_ioctls, M_FILECAPS); fdp->fd_ofiles[fd].fde_ioctls = NULL; fdp->fd_ofiles[fd].fde_nioctls = 0; } - if ((rights & CAP_FCNTL) == 0) + if (!cap_rights_is_set(&rights, CAP_FCNTL)) fdp->fd_ofiles[fd].fde_fcntls = 0; } FILEDESC_XUNLOCK(fdp); @@ -247,11 +275,14 @@ sys_cap_rights_limit(struct thread *td, struct cap_rights_limit_args *uap) * System call to query the rights mask associated with a capability. */ int -sys_cap_rights_get(struct thread *td, struct cap_rights_get_args *uap) +sys___cap_rights_get(struct thread *td, struct __cap_rights_get_args *uap) { struct filedesc *fdp; cap_rights_t rights; - int fd; + int error, fd, i, n; + + if (uap->version != CAP_RIGHTS_VERSION_00) + return (EINVAL); fd = uap->fd; @@ -263,9 +294,26 @@ sys_cap_rights_get(struct thread *td, struct cap_rights_get_args *uap) FILEDESC_SUNLOCK(fdp); return (EBADF); } - rights = cap_rights(fdp, fd); + rights = *cap_rights(fdp, fd); FILEDESC_SUNLOCK(fdp); - return (copyout(&rights, uap->rightsp, sizeof(*uap->rightsp))); + n = uap->version + 2; + if (uap->version != CAPVER(&rights)) { + /* + * For older versions we need to check if the descriptor + * doesn't contain rights not understood by the caller. + * If it does, we have to return an error. + */ + for (i = n; i < CAPARSIZE(&rights); i++) { + if ((rights.cr_rights[i] & ~(0x7FULL << 57)) != 0) + return (EINVAL); + } + } + error = copyout(&rights, uap->rightsp, sizeof(rights.cr_rights[0]) * n); +#ifdef KTRACE + if (error == 0 && KTRPOINT(td, KTR_STRUCT)) + ktrcaprights(&rights); +#endif + return (error); } /* @@ -513,65 +561,6 @@ sys_cap_fcntls_get(struct thread *td, struct cap_fcntls_get_args *uap) return (copyout(&rights, uap->fcntlrightsp, sizeof(rights))); } -/* - * For backward compatibility. - */ -int -sys_cap_new(struct thread *td, struct cap_new_args *uap) -{ - struct filedesc *fdp; - cap_rights_t rights; - register_t newfd; - int error, fd; - - fd = uap->fd; - rights = uap->rights; - - AUDIT_ARG_FD(fd); - AUDIT_ARG_RIGHTS(rights); - - if ((rights & ~CAP_ALL) != 0) - return (EINVAL); - - fdp = td->td_proc->p_fd; - FILEDESC_SLOCK(fdp); - if (fget_locked(fdp, fd) == NULL) { - FILEDESC_SUNLOCK(fdp); - return (EBADF); - } - error = _cap_check(cap_rights(fdp, fd), rights, CAPFAIL_INCREASE); - FILEDESC_SUNLOCK(fdp); - if (error != 0) - return (error); - - error = do_dup(td, 0, fd, 0, &newfd); - if (error != 0) - return (error); - - FILEDESC_XLOCK(fdp); - /* - * We don't really care about the race between checking capability - * rights for the source descriptor and now. If capability rights - * were ok at that earlier point, the process had this descriptor - * with those rights, so we don't increase them in security sense, - * the process might have done the cap_new(2) a bit earlier to get - * the same effect. - */ - fdp->fd_ofiles[newfd].fde_rights = rights; - if ((rights & CAP_IOCTL) == 0) { - free(fdp->fd_ofiles[newfd].fde_ioctls, M_FILECAPS); - fdp->fd_ofiles[newfd].fde_ioctls = NULL; - fdp->fd_ofiles[newfd].fde_nioctls = 0; - } - if ((rights & CAP_FCNTL) == 0) - fdp->fd_ofiles[newfd].fde_fcntls = 0; - FILEDESC_XUNLOCK(fdp); - - td->td_retval[0] = newfd; - - return (0); -} - #else /* !CAPABILITIES */ /* @@ -587,7 +576,7 @@ sys_cap_rights_limit(struct thread *td, struct cap_rights_limit_args *uap) } int -sys_cap_rights_get(struct thread *td, struct cap_rights_get_args *uap) +sys___cap_rights_get(struct thread *td, struct cap___rights_get_args *uap) { return (ENOSYS); @@ -621,11 +610,4 @@ sys_cap_fcntls_get(struct thread *td, struct cap_fcntls_get_args *uap) return (ENOSYS); } -int -sys_cap_new(struct thread *td, struct cap_new_args *uap) -{ - - return (ENOSYS); -} - #endif /* CAPABILITIES */ diff --git a/sys/kern/sys_generic.c b/sys/kern/sys_generic.c index 44d1a8994645..5eaa6958b050 100644 --- a/sys/kern/sys_generic.c +++ b/sys/kern/sys_generic.c @@ -243,9 +243,10 @@ int kern_readv(struct thread *td, int fd, struct uio *auio) { struct file *fp; + cap_rights_t rights; int error; - error = fget_read(td, fd, CAP_READ, &fp); + error = fget_read(td, fd, cap_rights_init(&rights, CAP_READ), &fp); if (error) return (error); error = dofileread(td, fd, fp, auio, (off_t)-1, 0); @@ -286,9 +287,10 @@ kern_preadv(td, fd, auio, offset) off_t offset; { struct file *fp; + cap_rights_t rights; int error; - error = fget_read(td, fd, CAP_PREAD, &fp); + error = fget_read(td, fd, cap_rights_init(&rights, CAP_PREAD), &fp); if (error) return (error); if (!(fp->f_ops->fo_flags & DFLAG_SEEKABLE)) @@ -452,9 +454,10 @@ int kern_writev(struct thread *td, int fd, struct uio *auio) { struct file *fp; + cap_rights_t rights; int error; - error = fget_write(td, fd, CAP_WRITE, &fp); + error = fget_write(td, fd, cap_rights_init(&rights, CAP_WRITE), &fp); if (error) return (error); error = dofilewrite(td, fd, fp, auio, (off_t)-1, 0); @@ -495,9 +498,10 @@ kern_pwritev(td, fd, auio, offset) off_t offset; { struct file *fp; + cap_rights_t rights; int error; - error = fget_write(td, fd, CAP_PWRITE, &fp); + error = fget_write(td, fd, cap_rights_init(&rights, CAP_PWRITE), &fp); if (error) return (error); if (!(fp->f_ops->fo_flags & DFLAG_SEEKABLE)) @@ -575,12 +579,13 @@ kern_ftruncate(td, fd, length) off_t length; { struct file *fp; + cap_rights_t rights; int error; AUDIT_ARG_FD(fd); if (length < 0) return (EINVAL); - error = fget(td, fd, CAP_FTRUNCATE, &fp); + error = fget(td, fd, cap_rights_init(&rights, CAP_FTRUNCATE), &fp); if (error) return (error); AUDIT_ARG_FILE(td->td_proc, fp); @@ -705,6 +710,9 @@ kern_ioctl(struct thread *td, int fd, u_long com, caddr_t data) { struct file *fp; struct filedesc *fdp; +#ifndef CAPABILITIES + cap_rights_t rights; +#endif int error, tmp, locked; AUDIT_ARG_FD(fd); @@ -743,7 +751,8 @@ kern_ioctl(struct thread *td, int fd, u_long com, caddr_t data) locked = LA_UNLOCKED; } #else - if ((error = fget(td, fd, CAP_IOCTL, &fp)) != 0) { + error = fget(td, fd, cap_rights_init(&rights, CAP_IOCTL), &fp); + if (error != 0) { fp = NULL; goto out; } @@ -1180,8 +1189,10 @@ selsetbits(fd_mask **ibits, fd_mask **obits, int idx, fd_mask bit, int events) static __inline int getselfd_cap(struct filedesc *fdp, int fd, struct file **fpp) { + cap_rights_t rights; - return (fget_unlocked(fdp, fd, CAP_POLL_EVENT, 0, fpp, NULL)); + return (fget_unlocked(fdp, fd, cap_rights_init(&rights, CAP_POLL_EVENT), + 0, fpp, NULL)); } /* @@ -1357,6 +1368,7 @@ pollrescan(struct thread *td) struct filedesc *fdp; struct file *fp; struct pollfd *fd; + cap_rights_t rights; int n; n = 0; @@ -1373,7 +1385,8 @@ pollrescan(struct thread *td) fp = fdp->fd_ofiles[fd->fd].fde_file; #ifdef CAPABILITIES if (fp == NULL || - cap_check(cap_rights(fdp, fd->fd), CAP_POLL_EVENT) != 0) + cap_check(cap_rights(fdp, fd->fd), + cap_rights_init(&rights, CAP_POLL_EVENT)) != 0) #else if (fp == NULL) #endif @@ -1431,6 +1444,7 @@ pollscan(td, fds, nfd) { struct filedesc *fdp = td->td_proc->p_fd; struct file *fp; + cap_rights_t rights; int i, n = 0; FILEDESC_SLOCK(fdp); @@ -1445,7 +1459,7 @@ pollscan(td, fds, nfd) #ifdef CAPABILITIES if (fp == NULL || cap_check(cap_rights(fdp, fds->fd), - CAP_POLL_EVENT) != 0) + cap_rights_init(&rights, CAP_POLL_EVENT)) != 0) #else if (fp == NULL) #endif diff --git a/sys/kern/sys_procdesc.c b/sys/kern/sys_procdesc.c index bacaf182e1c2..4bafeabaab48 100644 --- a/sys/kern/sys_procdesc.c +++ b/sys/kern/sys_procdesc.c @@ -138,14 +138,14 @@ SYSINIT(vfs, SI_SUB_VFS, SI_ORDER_ANY, procdesc_init, NULL); * died. */ int -procdesc_find(struct thread *td, int fd, cap_rights_t rights, +procdesc_find(struct thread *td, int fd, cap_rights_t *rightsp, struct proc **p) { struct procdesc *pd; struct file *fp; int error; - error = fget(td, fd, rights, &fp); + error = fget(td, fd, rightsp, &fp); if (error) return (error); if (fp->f_type != DTYPE_PROCDESC) { @@ -185,12 +185,12 @@ procdesc_pid(struct file *fp_procdesc) * Retrieve the PID associated with a process descriptor. */ int -kern_pdgetpid(struct thread *td, int fd, cap_rights_t rights, pid_t *pidp) +kern_pdgetpid(struct thread *td, int fd, cap_rights_t *rightsp, pid_t *pidp) { struct file *fp; int error; - error = fget(td, fd, rights, &fp); + error = fget(td, fd, rightsp, &fp); if (error) return (error); if (fp->f_type != DTYPE_PROCDESC) { @@ -209,11 +209,13 @@ out: int sys_pdgetpid(struct thread *td, struct pdgetpid_args *uap) { + cap_rights_t rights; pid_t pid; int error; AUDIT_ARG_FD(uap->fd); - error = kern_pdgetpid(td, uap->fd, CAP_PDGETPID, &pid); + error = kern_pdgetpid(td, uap->fd, + cap_rights_init(&rights, CAP_PDGETPID), &pid); if (error == 0) error = copyout(&pid, uap->pidp, sizeof(pid)); return (error); diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master index 789f95a5b4dd..e19e310578b6 100644 --- a/sys/kern/syscalls.master +++ b/sys/kern/syscalls.master @@ -917,9 +917,9 @@ 512 AUE_SHMCTL NOSTD { int shmctl(int shmid, int cmd, \ struct shmid_ds *buf); } 513 AUE_LPATHCONF STD { int lpathconf(char *path, int name); } -514 AUE_CAP_NEW STD { int cap_new(int fd, uint64_t rights); } -515 AUE_CAP_RIGHTS_GET STD { int cap_rights_get(int fd, \ - uint64_t *rightsp); } +514 AUE_NULL OBSOL cap_new +515 AUE_CAP_RIGHTS_GET STD { int __cap_rights_get(int version, \ + int fd, cap_rights_t *rightsp); } 516 AUE_CAP_ENTER STD { int cap_enter(void); } 517 AUE_CAP_GETMODE STD { int cap_getmode(u_int *modep); } 518 AUE_PDFORK STD { int pdfork(int *fdp, int flags); } @@ -957,7 +957,7 @@ struct __wrusage *wrusage, \ siginfo_t *info); } 533 AUE_CAP_RIGHTS_LIMIT STD { int cap_rights_limit(int fd, \ - uint64_t rights); } + cap_rights_t *rightsp); } 534 AUE_CAP_IOCTLS_LIMIT STD { int cap_ioctls_limit(int fd, \ const u_long *cmds, size_t ncmds); } 535 AUE_CAP_IOCTLS_GET STD { ssize_t cap_ioctls_get(int fd, \ diff --git a/sys/kern/tty.c b/sys/kern/tty.c index 02eccd7ca0ff..4fce6072d652 100644 --- a/sys/kern/tty.c +++ b/sys/kern/tty.c @@ -1837,11 +1837,13 @@ ttyhook_register(struct tty **rtp, struct proc *p, int fd, struct cdev *dev; struct cdevsw *cdp; struct filedesc *fdp; + cap_rights_t rights; int error, ref; /* Validate the file descriptor. */ fdp = p->p_fd; - error = fget_unlocked(fdp, fd, CAP_TTYHOOK, 0, &fp, NULL); + error = fget_unlocked(fdp, fd, cap_rights_init(&rights, CAP_TTYHOOK), + 0, &fp, NULL); if (error != 0) return (error); if (fp->f_ops == &badfileops) { diff --git a/sys/kern/uipc_mqueue.c b/sys/kern/uipc_mqueue.c index 62c54d332593..6a1bf7621560 100644 --- a/sys/kern/uipc_mqueue.c +++ b/sys/kern/uipc_mqueue.c @@ -2086,19 +2086,19 @@ sys_kmq_unlink(struct thread *td, struct kmq_unlink_args *uap) return (error); } -typedef int (*_fgetf)(struct thread *, int, cap_rights_t, struct file **); +typedef int (*_fgetf)(struct thread *, int, cap_rights_t *, struct file **); /* * Get message queue by giving file slot */ static int -_getmq(struct thread *td, int fd, cap_rights_t rights, _fgetf func, +_getmq(struct thread *td, int fd, cap_rights_t *rightsp, _fgetf func, struct file **fpp, struct mqfs_node **ppn, struct mqueue **pmq) { struct mqfs_node *pn; int error; - error = func(td, fd, rights, fpp); + error = func(td, fd, rightsp, fpp); if (error) return (error); if (&mqueueops != (*fpp)->f_ops) { @@ -2117,21 +2117,30 @@ static __inline int getmq(struct thread *td, int fd, struct file **fpp, struct mqfs_node **ppn, struct mqueue **pmq) { - return _getmq(td, fd, CAP_POLL_EVENT, fget, fpp, ppn, pmq); + cap_rights_t rights; + + return _getmq(td, fd, cap_rights_init(&rights, CAP_POLL_EVENT), fget, + fpp, ppn, pmq); } static __inline int getmq_read(struct thread *td, int fd, struct file **fpp, struct mqfs_node **ppn, struct mqueue **pmq) { - return _getmq(td, fd, CAP_READ, fget_read, fpp, ppn, pmq); + cap_rights_t rights; + + return _getmq(td, fd, cap_rights_init(&rights, CAP_READ), fget_read, + fpp, ppn, pmq); } static __inline int getmq_write(struct thread *td, int fd, struct file **fpp, struct mqfs_node **ppn, struct mqueue **pmq) { - return _getmq(td, fd, CAP_WRITE, fget_write, fpp, ppn, pmq); + cap_rights_t rights; + + return _getmq(td, fd, cap_rights_init(&rights, CAP_WRITE), fget_write, + fpp, ppn, pmq); } static int @@ -2238,6 +2247,7 @@ sys_kmq_timedsend(struct thread *td, struct kmq_timedsend_args *uap) static int kern_kmq_notify(struct thread *td, int mqd, struct sigevent *sigev) { + cap_rights_t rights; struct filedesc *fdp; struct proc *p; struct mqueue *mq; @@ -2269,7 +2279,8 @@ again: goto out; } #ifdef CAPABILITIES - error = cap_check(cap_rights(fdp, mqd), CAP_POLL_EVENT); + error = cap_check(cap_rights(fdp, mqd), + cap_rights_init(&rights, CAP_POLL_EVENT)); if (error) { FILEDESC_SUNLOCK(fdp); goto out; diff --git a/sys/kern/uipc_sem.c b/sys/kern/uipc_sem.c index 8c86cc4611e5..f641654e8a5e 100644 --- a/sys/kern/uipc_sem.c +++ b/sys/kern/uipc_sem.c @@ -116,7 +116,7 @@ static int ksem_create(struct thread *td, const char *path, semid_t *semidp, mode_t mode, unsigned int value, int flags, int compat32); static void ksem_drop(struct ksem *ks); -static int ksem_get(struct thread *td, semid_t id, cap_rights_t rights, +static int ksem_get(struct thread *td, semid_t id, cap_rights_t *rightsp, struct file **fpp); static struct ksem *ksem_hold(struct ksem *ks); static void ksem_insert(char *path, Fnv32_t fnv, struct ksem *ks); @@ -600,13 +600,14 @@ ksem_create(struct thread *td, const char *name, semid_t *semidp, mode_t mode, } static int -ksem_get(struct thread *td, semid_t id, cap_rights_t rights, struct file **fpp) +ksem_get(struct thread *td, semid_t id, cap_rights_t *rightsp, + struct file **fpp) { struct ksem *ks; struct file *fp; int error; - error = fget(td, id, rights, &fp); + error = fget(td, id, rightsp, &fp); if (error) return (EINVAL); if (fp->f_type != DTYPE_SEM) { @@ -720,11 +721,13 @@ struct ksem_post_args { int sys_ksem_post(struct thread *td, struct ksem_post_args *uap) { + cap_rights_t rights; struct file *fp; struct ksem *ks; int error; - error = ksem_get(td, uap->id, CAP_SEM_POST, &fp); + error = ksem_get(td, uap->id, + cap_rights_init(&rights, CAP_SEM_POST), &fp); if (error) return (error); ks = fp->f_data; @@ -809,12 +812,13 @@ kern_sem_wait(struct thread *td, semid_t id, int tryflag, { struct timespec ts1, ts2; struct timeval tv; + cap_rights_t rights; struct file *fp; struct ksem *ks; int error; DP((">>> kern_sem_wait entered! pid=%d\n", (int)td->td_proc->p_pid)); - error = ksem_get(td, id, CAP_SEM_WAIT, &fp); + error = ksem_get(td, id, cap_rights_init(&rights, CAP_SEM_WAIT), &fp); if (error) return (error); ks = fp->f_data; @@ -876,11 +880,13 @@ struct ksem_getvalue_args { int sys_ksem_getvalue(struct thread *td, struct ksem_getvalue_args *uap) { + cap_rights_t rights; struct file *fp; struct ksem *ks; int error, val; - error = ksem_get(td, uap->id, CAP_SEM_GETVALUE, &fp); + error = ksem_get(td, uap->id, + cap_rights_init(&rights, CAP_SEM_GETVALUE), &fp); if (error) return (error); ks = fp->f_data; diff --git a/sys/kern/uipc_syscalls.c b/sys/kern/uipc_syscalls.c index 72663a24cfd3..7e25da81759f 100644 --- a/sys/kern/uipc_syscalls.c +++ b/sys/kern/uipc_syscalls.c @@ -164,13 +164,13 @@ SYSCTL_PROC(_kern_ipc, OID_AUTO, sfstat, CTLTYPE_OPAQUE | CTLFLAG_RW, * A reference on the file entry is held upon returning. */ static int -getsock_cap(struct filedesc *fdp, int fd, cap_rights_t rights, +getsock_cap(struct filedesc *fdp, int fd, cap_rights_t *rightsp, struct file **fpp, u_int *fflagp) { struct file *fp; int error; - error = fget_unlocked(fdp, fd, rights, 0, &fp, NULL); + error = fget_unlocked(fdp, fd, rightsp, 0, &fp, NULL); if (error != 0) return (error); if (fp->f_type != DTYPE_SOCKET) { @@ -267,11 +267,13 @@ kern_bindat(struct thread *td, int dirfd, int fd, struct sockaddr *sa) { struct socket *so; struct file *fp; + cap_rights_t rights; int error; AUDIT_ARG_FD(fd); AUDIT_ARG_SOCKADDR(td, dirfd, sa); - error = getsock_cap(td->td_proc->p_fd, fd, CAP_BIND, &fp, NULL); + error = getsock_cap(td->td_proc->p_fd, fd, + cap_rights_init(&rights, CAP_BIND), &fp, NULL); if (error) return (error); so = fp->f_data; @@ -334,10 +336,12 @@ sys_listen(td, uap) { struct socket *so; struct file *fp; + cap_rights_t rights; int error; AUDIT_ARG_FD(uap->s); - error = getsock_cap(td->td_proc->p_fd, uap->s, CAP_LISTEN, &fp, NULL); + error = getsock_cap(td->td_proc->p_fd, uap->s, + cap_rights_init(&rights, CAP_LISTEN), &fp, NULL); if (error == 0) { so = fp->f_data; #ifdef MAC @@ -419,6 +423,7 @@ kern_accept4(struct thread *td, int s, struct sockaddr **name, int error; struct socket *head, *so; int fd; + cap_rights_t rights; u_int fflag; pid_t pgid; int tmp; @@ -428,7 +433,8 @@ kern_accept4(struct thread *td, int s, struct sockaddr **name, AUDIT_ARG_FD(s); fdp = td->td_proc->p_fd; - error = getsock_cap(fdp, s, CAP_ACCEPT, &headfp, &fflag); + error = getsock_cap(fdp, s, cap_rights_init(&rights, CAP_ACCEPT), + &headfp, &fflag); if (error) return (error); head = headfp->f_data; @@ -629,12 +635,14 @@ kern_connectat(struct thread *td, int dirfd, int fd, struct sockaddr *sa) { struct socket *so; struct file *fp; + cap_rights_t rights; int error; int interrupted = 0; AUDIT_ARG_FD(fd); AUDIT_ARG_SOCKADDR(td, dirfd, sa); - error = getsock_cap(td->td_proc->p_fd, fd, CAP_CONNECT, &fp, NULL); + error = getsock_cap(td->td_proc->p_fd, fd, + cap_rights_init(&rights, CAP_CONNECT), &fp, NULL); if (error) return (error); so = fp->f_data; @@ -898,12 +906,12 @@ kern_sendit(td, s, mp, flags, control, segflg) #endif AUDIT_ARG_FD(s); - rights = CAP_SEND; + cap_rights_init(&rights, CAP_SEND); if (mp->msg_name != NULL) { AUDIT_ARG_SOCKADDR(td, AT_FDCWD, mp->msg_name); - rights |= CAP_CONNECT; + cap_rights_set(&rights, CAP_CONNECT); } - error = getsock_cap(td->td_proc->p_fd, s, rights, &fp, NULL); + error = getsock_cap(td->td_proc->p_fd, s, &rights, &fp, NULL); if (error) return (error); so = (struct socket *)fp->f_data; @@ -1099,6 +1107,7 @@ kern_recvit(td, s, mp, fromseg, controlp) struct file *fp; struct socket *so; struct sockaddr *fromsa = NULL; + cap_rights_t rights; #ifdef KTRACE struct uio *ktruio = NULL; #endif @@ -1107,7 +1116,8 @@ kern_recvit(td, s, mp, fromseg, controlp) *controlp = NULL; AUDIT_ARG_FD(s); - error = getsock_cap(td->td_proc->p_fd, s, CAP_RECV, &fp, NULL); + error = getsock_cap(td->td_proc->p_fd, s, + cap_rights_init(&rights, CAP_RECV), &fp, NULL); if (error) return (error); so = fp->f_data; @@ -1420,11 +1430,12 @@ sys_shutdown(td, uap) { struct socket *so; struct file *fp; + cap_rights_t rights; int error; AUDIT_ARG_FD(uap->s); - error = getsock_cap(td->td_proc->p_fd, uap->s, CAP_SHUTDOWN, &fp, - NULL); + error = getsock_cap(td->td_proc->p_fd, uap->s, + cap_rights_init(&rights, CAP_SHUTDOWN), &fp, NULL); if (error == 0) { so = fp->f_data; error = soshutdown(so, uap->how); @@ -1464,6 +1475,7 @@ kern_setsockopt(td, s, level, name, val, valseg, valsize) struct socket *so; struct file *fp; struct sockopt sopt; + cap_rights_t rights; if (val == NULL && valsize != 0) return (EFAULT); @@ -1487,7 +1499,8 @@ kern_setsockopt(td, s, level, name, val, valseg, valsize) } AUDIT_ARG_FD(s); - error = getsock_cap(td->td_proc->p_fd, s, CAP_SETSOCKOPT, &fp, NULL); + error = getsock_cap(td->td_proc->p_fd, s, + cap_rights_init(&rights, CAP_SETSOCKOPT), &fp, NULL); if (error == 0) { so = fp->f_data; error = sosetopt(so, &sopt); @@ -1543,6 +1556,7 @@ kern_getsockopt(td, s, level, name, val, valseg, valsize) struct socket *so; struct file *fp; struct sockopt sopt; + cap_rights_t rights; if (val == NULL) *valsize = 0; @@ -1566,7 +1580,8 @@ kern_getsockopt(td, s, level, name, val, valseg, valsize) } AUDIT_ARG_FD(s); - error = getsock_cap(td->td_proc->p_fd, s, CAP_GETSOCKOPT, &fp, NULL); + error = getsock_cap(td->td_proc->p_fd, s, + cap_rights_init(&rights, CAP_GETSOCKOPT), &fp, NULL); if (error == 0) { so = fp->f_data; error = sogetopt(so, &sopt); @@ -1621,11 +1636,13 @@ kern_getsockname(struct thread *td, int fd, struct sockaddr **sa, { struct socket *so; struct file *fp; + cap_rights_t rights; socklen_t len; int error; AUDIT_ARG_FD(fd); - error = getsock_cap(td->td_proc->p_fd, fd, CAP_GETSOCKNAME, &fp, NULL); + error = getsock_cap(td->td_proc->p_fd, fd, + cap_rights_init(&rights, CAP_GETSOCKNAME), &fp, NULL); if (error) return (error); so = fp->f_data; @@ -1718,11 +1735,13 @@ kern_getpeername(struct thread *td, int fd, struct sockaddr **sa, { struct socket *so; struct file *fp; + cap_rights_t rights; socklen_t len; int error; AUDIT_ARG_FD(fd); - error = getsock_cap(td->td_proc->p_fd, fd, CAP_GETPEERNAME, &fp, NULL); + error = getsock_cap(td->td_proc->p_fd, fd, + cap_rights_init(&rights, CAP_GETPEERNAME), &fp, NULL); if (error) return (error); so = fp->f_data; @@ -1907,6 +1926,7 @@ do_sendfile(struct thread *td, struct sendfile_args *uap, int compat) struct sf_hdtr hdtr; struct uio *hdr_uio, *trl_uio; struct file *fp; + cap_rights_t rights; int error; if (uap->offset < 0) @@ -1937,8 +1957,10 @@ do_sendfile(struct thread *td, struct sendfile_args *uap, int compat) * sendfile(2) can start at any offset within a file so we require * CAP_READ+CAP_SEEK = CAP_PREAD. */ - if ((error = fget_read(td, uap->fd, CAP_PREAD, &fp)) != 0) + if ((error = fget_read(td, uap->fd, + cap_rights_init(&rights, CAP_PREAD), &fp)) != 0) { goto out; + } error = fo_sendfile(fp, uap->s, hdr_uio, trl_uio, uap->offset, uap->nbytes, uap->sbytes, uap->flags, compat ? SFK_COMPAT : 0, td); @@ -1983,6 +2005,7 @@ vn_sendfile(struct file *fp, int sockfd, struct uio *hdr_uio, struct sf_buf *sf; struct vm_page *pg; struct vattr va; + cap_rights_t rights; off_t off, xfsize, fsbytes = 0, sbytes = 0, rem = 0; int error, hdrlen = 0, mnw = 0; int bsize; @@ -2030,8 +2053,9 @@ vn_sendfile(struct file *fp, int sockfd, struct uio *hdr_uio, * The socket must be a stream socket and connected. * Remember if it a blocking or non-blocking socket. */ - if ((error = getsock_cap(td->td_proc->p_fd, sockfd, CAP_SEND, - &sock_fp, NULL)) != 0) + error = getsock_cap(td->td_proc->p_fd, sockfd, + cap_rights_init(&rights, CAP_SEND), &sock_fp, NULL); + if (error != 0) goto out; so = sock_fp->f_data; if (so->so_type != SOCK_STREAM) { @@ -2463,10 +2487,12 @@ sys_sctp_peeloff(td, uap) int error; struct socket *head, *so; int fd; + cap_rights_t rights; u_int fflag; AUDIT_ARG_FD(uap->sd); - error = fgetsock(td, uap->sd, CAP_PEELOFF, &head, &fflag); + error = fgetsock(td, uap->sd, cap_rights_init(&rights, CAP_PEELOFF), + &head, &fflag); if (error) goto done2; if (head->so_proto->pr_protocol != IPPROTO_SCTP) { @@ -2574,18 +2600,18 @@ sys_sctp_generic_sendmsg (td, uap) u_sinfo = &sinfo; } - rights = CAP_SEND; + cap_rights_init(&rights, CAP_SEND); if (uap->tolen) { error = getsockaddr(&to, uap->to, uap->tolen); if (error) { to = NULL; goto sctp_bad2; } - rights |= CAP_CONNECT; + cap_rights_set(&rights, CAP_CONNECT); } AUDIT_ARG_FD(uap->sd); - error = getsock_cap(td->td_proc->p_fd, uap->sd, rights, &fp, NULL); + error = getsock_cap(td->td_proc->p_fd, uap->sd, &rights, &fp, NULL); if (error) goto sctp_bad; #ifdef KTRACE @@ -2685,18 +2711,18 @@ sys_sctp_generic_sendmsg_iov(td, uap) return (error); u_sinfo = &sinfo; } - rights = CAP_SEND; + cap_rights_init(&rights, CAP_SEND); if (uap->tolen) { error = getsockaddr(&to, uap->to, uap->tolen); if (error) { to = NULL; goto sctp_bad2; } - rights |= CAP_CONNECT; + cap_rights_set(&rights, CAP_CONNECT); } AUDIT_ARG_FD(uap->sd); - error = getsock_cap(td->td_proc->p_fd, uap->sd, rights, &fp, NULL); + error = getsock_cap(td->td_proc->p_fd, uap->sd, &rights, &fp, NULL); if (error) goto sctp_bad1; @@ -2804,12 +2830,14 @@ sys_sctp_generic_recvmsg(td, uap) ssize_t len; int i, msg_flags; int error = 0; + cap_rights_t rights; #ifdef KTRACE struct uio *ktruio = NULL; #endif AUDIT_ARG_FD(uap->sd); - error = getsock_cap(td->td_proc->p_fd, uap->sd, CAP_RECV, &fp, NULL); + error = getsock_cap(td->td_proc->p_fd, uap->sd, + cap_rights_init(&rights, CAP_RECV), &fp, NULL); if (error) { return (error); } diff --git a/sys/kern/uipc_usrreq.c b/sys/kern/uipc_usrreq.c index 7a4db04130fe..c0a5d2eb5f40 100644 --- a/sys/kern/uipc_usrreq.c +++ b/sys/kern/uipc_usrreq.c @@ -464,6 +464,7 @@ uipc_bindat(int fd, struct socket *so, struct sockaddr *nam, struct thread *td) struct unpcb *unp; struct vnode *vp; struct mount *mp; + cap_rights_t rights; char *buf; unp = sotounpcb(so); @@ -502,7 +503,7 @@ uipc_bindat(int fd, struct socket *so, struct sockaddr *nam, struct thread *td) restart: NDINIT_ATRIGHTS(&nd, CREATE, NOFOLLOW | LOCKPARENT | SAVENAME, - UIO_SYSSPACE, buf, fd, CAP_BINDAT, td); + UIO_SYSSPACE, buf, fd, cap_rights_init(&rights, CAP_BINDAT), td); /* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */ error = namei(&nd); if (error) @@ -1276,10 +1277,11 @@ unp_connectat(int fd, struct socket *so, struct sockaddr *nam, struct vnode *vp; struct socket *so2, *so3; struct unpcb *unp, *unp2, *unp3; - int error, len; struct nameidata nd; char buf[SOCK_MAXADDRLEN]; struct sockaddr *sa; + cap_rights_t rights; + int error, len; UNP_LINK_WLOCK_ASSERT(); @@ -1305,7 +1307,7 @@ unp_connectat(int fd, struct socket *so, struct sockaddr *nam, sa = malloc(sizeof(struct sockaddr_un), M_SONAME, M_WAITOK); NDINIT_ATRIGHTS(&nd, LOOKUP, FOLLOW | LOCKSHARED | LOCKLEAF, - UIO_SYSSPACE, buf, fd, CAP_CONNECTAT, td); + UIO_SYSSPACE, buf, fd, cap_rights_init(&rights, CAP_CONNECTAT), td); error = namei(&nd); if (error) vp = NULL; diff --git a/sys/kern/vfs_acl.c b/sys/kern/vfs_acl.c index 1c9923d9d2a8..362792b46dce 100644 --- a/sys/kern/vfs_acl.c +++ b/sys/kern/vfs_acl.c @@ -399,9 +399,11 @@ int sys___acl_get_fd(struct thread *td, struct __acl_get_fd_args *uap) { struct file *fp; + cap_rights_t rights; int error; - error = getvnode(td->td_proc->p_fd, uap->filedes, CAP_ACL_GET, &fp); + error = getvnode(td->td_proc->p_fd, uap->filedes, + cap_rights_init(&rights, CAP_ACL_GET), &fp); if (error == 0) { error = vacl_get_acl(td, fp->f_vnode, uap->type, uap->aclp); fdrop(fp, td); @@ -416,9 +418,11 @@ int sys___acl_set_fd(struct thread *td, struct __acl_set_fd_args *uap) { struct file *fp; + cap_rights_t rights; int error; - error = getvnode(td->td_proc->p_fd, uap->filedes, CAP_ACL_SET, &fp); + error = getvnode(td->td_proc->p_fd, uap->filedes, + cap_rights_init(&rights, CAP_ACL_SET), &fp); if (error == 0) { error = vacl_set_acl(td, fp->f_vnode, uap->type, uap->aclp); fdrop(fp, td); @@ -469,10 +473,11 @@ int sys___acl_delete_fd(struct thread *td, struct __acl_delete_fd_args *uap) { struct file *fp; + cap_rights_t rights; int error; - error = getvnode(td->td_proc->p_fd, uap->filedes, CAP_ACL_DELETE, - &fp); + error = getvnode(td->td_proc->p_fd, uap->filedes, + cap_rights_init(&rights, CAP_ACL_DELETE), &fp); if (error == 0) { error = vacl_delete(td, fp->f_vnode, uap->type); fdrop(fp, td); @@ -523,10 +528,11 @@ int sys___acl_aclcheck_fd(struct thread *td, struct __acl_aclcheck_fd_args *uap) { struct file *fp; + cap_rights_t rights; int error; - error = getvnode(td->td_proc->p_fd, uap->filedes, CAP_ACL_CHECK, - &fp); + error = getvnode(td->td_proc->p_fd, uap->filedes, + cap_rights_init(&rights, CAP_ACL_CHECK), &fp); if (error == 0) { error = vacl_aclcheck(td, fp->f_vnode, uap->type, uap->aclp); fdrop(fp, td); diff --git a/sys/kern/vfs_aio.c b/sys/kern/vfs_aio.c index a66f7c20c233..9f3adaf2ff0a 100644 --- a/sys/kern/vfs_aio.c +++ b/sys/kern/vfs_aio.c @@ -1567,6 +1567,7 @@ aio_aqueue(struct thread *td, struct aiocb *job, struct aioliojob *lj, int type, struct aiocb_ops *ops) { struct proc *p = td->td_proc; + cap_rights_t rights; struct file *fp; struct socket *so; struct aiocblist *aiocbe, *cb; @@ -1647,19 +1648,21 @@ aio_aqueue(struct thread *td, struct aiocb *job, struct aioliojob *lj, fd = aiocbe->uaiocb.aio_fildes; switch (opcode) { case LIO_WRITE: - error = fget_write(td, fd, CAP_PWRITE, &fp); + error = fget_write(td, fd, + cap_rights_init(&rights, CAP_PWRITE), &fp); break; case LIO_READ: - error = fget_read(td, fd, CAP_PREAD, &fp); + error = fget_read(td, fd, + cap_rights_init(&rights, CAP_PREAD), &fp); break; case LIO_SYNC: - error = fget(td, fd, CAP_FSYNC, &fp); + error = fget(td, fd, cap_rights_init(&rights, CAP_FSYNC), &fp); break; case LIO_MLOCK: fp = NULL; break; case LIO_NOP: - error = fget(td, fd, CAP_NONE, &fp); + error = fget(td, fd, cap_rights_init(&rights), &fp); break; default: error = EINVAL; diff --git a/sys/kern/vfs_extattr.c b/sys/kern/vfs_extattr.c index 700a70c2c5e8..bc7b942525e7 100644 --- a/sys/kern/vfs_extattr.c +++ b/sys/kern/vfs_extattr.c @@ -216,6 +216,7 @@ sys_extattr_set_fd(td, uap) { struct file *fp; char attrname[EXTATTR_MAXNAMELEN]; + cap_rights_t rights; int error; AUDIT_ARG_FD(uap->fd); @@ -225,7 +226,8 @@ sys_extattr_set_fd(td, uap) return (error); AUDIT_ARG_TEXT(attrname); - error = getvnode(td->td_proc->p_fd, uap->fd, CAP_EXTATTR_SET, &fp); + error = getvnode(td->td_proc->p_fd, uap->fd, + cap_rights_init(&rights, CAP_EXTATTR_SET), &fp); if (error) return (error); @@ -389,6 +391,7 @@ sys_extattr_get_fd(td, uap) { struct file *fp; char attrname[EXTATTR_MAXNAMELEN]; + cap_rights_t rights; int error; AUDIT_ARG_FD(uap->fd); @@ -398,7 +401,8 @@ sys_extattr_get_fd(td, uap) return (error); AUDIT_ARG_TEXT(attrname); - error = getvnode(td->td_proc->p_fd, uap->fd, CAP_EXTATTR_GET, &fp); + error = getvnode(td->td_proc->p_fd, uap->fd, + cap_rights_init(&rights, CAP_EXTATTR_GET), &fp); if (error) return (error); @@ -531,6 +535,7 @@ sys_extattr_delete_fd(td, uap) { struct file *fp; char attrname[EXTATTR_MAXNAMELEN]; + cap_rights_t rights; int error; AUDIT_ARG_FD(uap->fd); @@ -540,8 +545,8 @@ sys_extattr_delete_fd(td, uap) return (error); AUDIT_ARG_TEXT(attrname); - error = getvnode(td->td_proc->p_fd, uap->fd, CAP_EXTATTR_DELETE, - &fp); + error = getvnode(td->td_proc->p_fd, uap->fd, + cap_rights_init(&rights, CAP_EXTATTR_DELETE), &fp); if (error) return (error); @@ -687,11 +692,13 @@ sys_extattr_list_fd(td, uap) } */ *uap; { struct file *fp; + cap_rights_t rights; int error; AUDIT_ARG_FD(uap->fd); AUDIT_ARG_VALUE(uap->attrnamespace); - error = getvnode(td->td_proc->p_fd, uap->fd, CAP_EXTATTR_LIST, &fp); + error = getvnode(td->td_proc->p_fd, uap->fd, + cap_rights_init(&rights, CAP_EXTATTR_LIST), &fp); if (error) return (error); diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c index 7fe19085dd4b..d4d01665a991 100644 --- a/sys/kern/vfs_lookup.c +++ b/sys/kern/vfs_lookup.c @@ -222,20 +222,26 @@ namei(struct nameidata *ndp) dp = ndp->ni_startdir; error = 0; } else if (ndp->ni_dirfd != AT_FDCWD) { + cap_rights_t rights; + + rights = ndp->ni_rightsneeded; + cap_rights_set(&rights, CAP_LOOKUP); + if (cnp->cn_flags & AUDITVNODE1) AUDIT_ARG_ATFD1(ndp->ni_dirfd); if (cnp->cn_flags & AUDITVNODE2) AUDIT_ARG_ATFD2(ndp->ni_dirfd); error = fgetvp_rights(td, ndp->ni_dirfd, - ndp->ni_rightsneeded | CAP_LOOKUP, - &ndp->ni_filecaps, &dp); + &rights, &ndp->ni_filecaps, &dp); #ifdef CAPABILITIES /* * If file descriptor doesn't have all rights, * all lookups relative to it must also be * strictly relative. */ - if (ndp->ni_filecaps.fc_rights != CAP_ALL || + CAP_ALL(&rights); + if (!cap_rights_contains(&ndp->ni_filecaps.fc_rights, + &rights) || ndp->ni_filecaps.fc_fcntls != CAP_FCNTL_ALL || ndp->ni_filecaps.fc_nioctls != -1) { ndp->ni_strictrelative = 1; @@ -1059,6 +1065,27 @@ bad: return (error); } +void +NDINIT_ALL(struct nameidata *ndp, u_long op, u_long flags, enum uio_seg segflg, + const char *namep, int dirfd, struct vnode *startdir, cap_rights_t *rightsp, + struct thread *td) +{ + + ndp->ni_cnd.cn_nameiop = op; + ndp->ni_cnd.cn_flags = flags; + ndp->ni_segflg = segflg; + ndp->ni_dirp = namep; + ndp->ni_dirfd = dirfd; + ndp->ni_startdir = startdir; + ndp->ni_strictrelative = 0; + if (rightsp != NULL) + ndp->ni_rightsneeded = *rightsp; + else + cap_rights_init(&ndp->ni_rightsneeded); + filecaps_init(&ndp->ni_filecaps); + ndp->ni_cnd.cn_thread = td; +} + /* * Free data allocated by namei(); see namei(9) for details. */ diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index 2877ad2535e3..7df315d1decb 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -367,10 +367,12 @@ kern_fstatfs(struct thread *td, int fd, struct statfs *buf) struct mount *mp; struct statfs *sp, sb; struct vnode *vp; + cap_rights_t rights; int error; AUDIT_ARG_FD(fd); - error = getvnode(td->td_proc->p_fd, fd, CAP_FSTATFS, &fp); + error = getvnode(td->td_proc->p_fd, fd, + cap_rights_init(&rights, CAP_FSTATFS), &fp); if (error) return (error); vp = fp->f_vnode; @@ -730,10 +732,13 @@ sys_fchdir(td, uap) struct vnode *vp, *tdp, *vpold; struct mount *mp; struct file *fp; + cap_rights_t rights; int error; AUDIT_ARG_FD(uap->fd); - if ((error = getvnode(fdp, uap->fd, CAP_FCHDIR, &fp)) != 0) + error = getvnode(fdp, uap->fd, cap_rights_init(&rights, CAP_FCHDIR), + &fp); + if (error != 0) return (error); vp = fp->f_vnode; VREF(vp); @@ -954,42 +959,39 @@ change_root(vp, td) return (0); } -static __inline cap_rights_t -flags_to_rights(int flags) +static __inline void +flags_to_rights(int flags, cap_rights_t *rightsp) { - cap_rights_t rights = 0; if (flags & O_EXEC) { - rights |= CAP_FEXECVE; + cap_rights_set(rightsp, CAP_FEXECVE); } else { switch ((flags & O_ACCMODE)) { case O_RDONLY: - rights |= CAP_READ; + cap_rights_set(rightsp, CAP_READ); break; case O_RDWR: - rights |= CAP_READ; + cap_rights_set(rightsp, CAP_READ); /* FALLTHROUGH */ case O_WRONLY: - rights |= CAP_WRITE; + cap_rights_set(rightsp, CAP_WRITE); if (!(flags & (O_APPEND | O_TRUNC))) - rights |= CAP_SEEK; + cap_rights_set(rightsp, CAP_SEEK); break; } } if (flags & O_CREAT) - rights |= CAP_CREATE; + cap_rights_set(rightsp, CAP_CREATE); if (flags & O_TRUNC) - rights |= CAP_FTRUNCATE; + cap_rights_set(rightsp, CAP_FTRUNCATE); if (flags & (O_SYNC | O_FSYNC)) - rights |= CAP_FSYNC; + cap_rights_set(rightsp, CAP_FSYNC); if (flags & (O_EXLOCK | O_SHLOCK)) - rights |= CAP_FLOCK; - - return (rights); + cap_rights_set(rightsp, CAP_FLOCK); } /* @@ -1051,12 +1053,13 @@ kern_openat(struct thread *td, int fd, char *path, enum uio_seg pathseg, int cmode; int indx = -1, error; struct nameidata nd; - cap_rights_t rights_needed = CAP_LOOKUP; + cap_rights_t rights; AUDIT_ARG_FFLAGS(flags); AUDIT_ARG_MODE(mode); /* XXX: audit dirfd */ - rights_needed |= flags_to_rights(flags); + cap_rights_init(&rights, CAP_LOOKUP); + flags_to_rights(flags, &rights); /* * Only one of the O_EXEC, O_RDONLY, O_WRONLY and O_RDWR flags * may be specified. @@ -1084,7 +1087,7 @@ kern_openat(struct thread *td, int fd, char *path, enum uio_seg pathseg, fp->f_flag = flags & FMASK; cmode = ((mode &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT; NDINIT_ATRIGHTS(&nd, LOOKUP, FOLLOW | AUDITVNODE1, pathseg, path, fd, - rights_needed, td); + &rights, td); td->td_dupfd = -1; /* XXX check for fdopen */ error = vn_open(&nd, &flags, cmode, fp); if (error) { @@ -1258,6 +1261,7 @@ kern_mknodat(struct thread *td, int fd, char *path, enum uio_seg pathseg, int error; int whiteout = 0; struct nameidata nd; + cap_rights_t rights; AUDIT_ARG_MODE(mode); AUDIT_ARG_DEV(dev); @@ -1285,7 +1289,7 @@ kern_mknodat(struct thread *td, int fd, char *path, enum uio_seg pathseg, restart: bwillwrite(); NDINIT_ATRIGHTS(&nd, CREATE, LOCKPARENT | SAVENAME | AUDITVNODE1, - pathseg, path, fd, CAP_MKNODAT, td); + pathseg, path, fd, cap_rights_init(&rights, CAP_MKNODAT), td); if ((error = namei(&nd)) != 0) return (error); vp = nd.ni_vp; @@ -1398,6 +1402,7 @@ kern_mkfifoat(struct thread *td, int fd, char *path, enum uio_seg pathseg, { struct mount *mp; struct vattr vattr; + cap_rights_t rights; int error; struct nameidata nd; @@ -1405,7 +1410,7 @@ kern_mkfifoat(struct thread *td, int fd, char *path, enum uio_seg pathseg, restart: bwillwrite(); NDINIT_ATRIGHTS(&nd, CREATE, LOCKPARENT | SAVENAME | AUDITVNODE1, - pathseg, path, fd, CAP_MKFIFOAT, td); + pathseg, path, fd, cap_rights_init(&rights, CAP_MKFIFOAT), td); if ((error = namei(&nd)) != 0) return (error); if (nd.ni_vp != NULL) { @@ -1541,6 +1546,7 @@ kern_linkat(struct thread *td, int fd1, int fd2, char *path1, char *path2, struct vnode *vp; struct mount *mp; struct nameidata nd; + cap_rights_t rights; int error; bwillwrite(); @@ -1559,7 +1565,7 @@ kern_linkat(struct thread *td, int fd1, int fd2, char *path1, char *path2, return (error); } NDINIT_ATRIGHTS(&nd, CREATE, LOCKPARENT | SAVENAME | AUDITVNODE2, - segflg, path2, fd2, CAP_LINKAT, td); + segflg, path2, fd2, cap_rights_init(&rights, CAP_LINKAT), td); if ((error = namei(&nd)) == 0) { if (nd.ni_vp != NULL) { if (nd.ni_dvp == nd.ni_vp) @@ -1640,6 +1646,7 @@ kern_symlinkat(struct thread *td, char *path1, int fd, char *path2, char *syspath; int error; struct nameidata nd; + cap_rights_t rights; if (segflg == UIO_SYSSPACE) { syspath = path1; @@ -1652,7 +1659,7 @@ kern_symlinkat(struct thread *td, char *path1, int fd, char *path2, restart: bwillwrite(); NDINIT_ATRIGHTS(&nd, CREATE, LOCKPARENT | SAVENAME | AUDITVNODE1, - segflg, path2, fd, CAP_SYMLINKAT, td); + segflg, path2, fd, cap_rights_init(&rights, CAP_SYMLINKAT), td); if ((error = namei(&nd)) != 0) goto out; if (nd.ni_vp) { @@ -1800,11 +1807,12 @@ kern_unlinkat(struct thread *td, int fd, char *path, enum uio_seg pathseg, int error; struct nameidata nd; struct stat sb; + cap_rights_t rights; restart: bwillwrite(); NDINIT_ATRIGHTS(&nd, DELETE, LOCKPARENT | LOCKLEAF | AUDITVNODE1, - pathseg, path, fd, CAP_UNLINKAT, td); + pathseg, path, fd, cap_rights_init(&rights, CAP_UNLINKAT), td); if ((error = namei(&nd)) != 0) return (error == EINVAL ? EPERM : error); vp = nd.ni_vp; @@ -1880,10 +1888,12 @@ sys_lseek(td, uap) } */ *uap; { struct file *fp; + cap_rights_t rights; int error; AUDIT_ARG_FD(uap->fd); - if ((error = fget(td, uap->fd, CAP_SEEK, &fp)) != 0) + error = fget(td, uap->fd, cap_rights_init(&rights, CAP_SEEK), &fp); + if (error != 0) return (error); error = (fp->f_ops->fo_flags & DFLAG_SEEKABLE) != 0 ? fo_seek(fp, uap->offset, uap->whence, td) : ESPIPE; @@ -2026,6 +2036,7 @@ kern_accessat(struct thread *td, int fd, char *path, enum uio_seg pathseg, struct ucred *cred, *tmpcred; struct vnode *vp; struct nameidata nd; + cap_rights_t rights; int error; /* @@ -2042,7 +2053,8 @@ kern_accessat(struct thread *td, int fd, char *path, enum uio_seg pathseg, cred = tmpcred = td->td_ucred; AUDIT_ARG_VALUE(amode); NDINIT_ATRIGHTS(&nd, LOOKUP, FOLLOW | LOCKSHARED | LOCKLEAF | - AUDITVNODE1, pathseg, path, fd, CAP_FSTAT, td); + AUDITVNODE1, pathseg, path, fd, cap_rights_init(&rights, CAP_FSTAT), + td); if ((error = namei(&nd)) != 0) goto out1; vp = nd.ni_vp; @@ -2244,6 +2256,7 @@ kern_statat_vnhook(struct thread *td, int flag, int fd, char *path, { struct nameidata nd; struct stat sb; + cap_rights_t rights; int error; if (flag & ~AT_SYMLINK_NOFOLLOW) @@ -2251,7 +2264,7 @@ kern_statat_vnhook(struct thread *td, int flag, int fd, char *path, NDINIT_ATRIGHTS(&nd, LOOKUP, ((flag & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW : FOLLOW) | LOCKSHARED | LOCKLEAF | AUDITVNODE1, pathseg, path, fd, - CAP_FSTAT, td); + cap_rights_init(&rights, CAP_FSTAT), td); if ((error = namei(&nd)) != 0) return (error); @@ -2663,12 +2676,13 @@ kern_chflagsat(struct thread *td, int fd, const char *path, enum uio_seg pathseg, u_long flags, int atflag) { struct nameidata nd; + cap_rights_t rights; int error, follow; AUDIT_ARG_FFLAGS(flags); follow = (atflag & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW : FOLLOW; NDINIT_ATRIGHTS(&nd, LOOKUP, follow | AUDITVNODE1, pathseg, path, fd, - CAP_FCHFLAGS, td); + cap_rights_init(&rights, CAP_FCHFLAGS), td); if ((error = namei(&nd)) != 0) return (error); NDFREE(&nd, NDF_ONLY_PNBUF); @@ -2695,12 +2709,14 @@ sys_fchflags(td, uap) } */ *uap; { struct file *fp; + cap_rights_t rights; int error; AUDIT_ARG_FD(uap->fd); AUDIT_ARG_FFLAGS(uap->flags); - if ((error = getvnode(td->td_proc->p_fd, uap->fd, CAP_FCHFLAGS, - &fp)) != 0) + error = getvnode(td->td_proc->p_fd, uap->fd, + cap_rights_init(&rights, CAP_FCHFLAGS), &fp); + if (error != 0) return (error); #ifdef AUDIT vn_lock(fp->f_vnode, LK_SHARED | LK_RETRY); @@ -2820,11 +2836,12 @@ kern_fchmodat(struct thread *td, int fd, char *path, enum uio_seg pathseg, int error; struct nameidata nd; int follow; + cap_rights_t rights; AUDIT_ARG_MODE(mode); follow = (flag & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW : FOLLOW; NDINIT_ATRIGHTS(&nd, LOOKUP, follow | AUDITVNODE1, pathseg, path, fd, - CAP_FCHMOD, td); + cap_rights_init(&rights, CAP_FCHMOD), td); if ((error = namei(&nd)) != 0) return (error); NDFREE(&nd, NDF_ONLY_PNBUF); @@ -2846,12 +2863,13 @@ int sys_fchmod(struct thread *td, struct fchmod_args *uap) { struct file *fp; + cap_rights_t rights; int error; AUDIT_ARG_FD(uap->fd); AUDIT_ARG_MODE(uap->mode); - error = fget(td, uap->fd, CAP_FCHMOD, &fp); + error = fget(td, uap->fd, cap_rights_init(&rights, CAP_FCHMOD), &fp); if (error != 0) return (error); error = fo_chmod(fp, uap->mode, td->td_ucred, td); @@ -2949,12 +2967,13 @@ kern_fchownat(struct thread *td, int fd, char *path, enum uio_seg pathseg, int uid, int gid, int flag) { struct nameidata nd; + cap_rights_t rights; int error, follow; AUDIT_ARG_OWNER(uid, gid); follow = (flag & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW : FOLLOW; NDINIT_ATRIGHTS(&nd, LOOKUP, follow | AUDITVNODE1, pathseg, path, fd, - CAP_FCHOWN, td); + cap_rights_init(&rights, CAP_FCHOWN), td); if ((error = namei(&nd)) != 0) return (error); @@ -3016,11 +3035,12 @@ sys_fchown(td, uap) } */ *uap; { struct file *fp; + cap_rights_t rights; int error; AUDIT_ARG_FD(uap->fd); AUDIT_ARG_OWNER(uap->uid, uap->gid); - error = fget(td, uap->fd, CAP_FCHOWN, &fp); + error = fget(td, uap->fd, cap_rights_init(&rights, CAP_FCHOWN), &fp); if (error != 0) return (error); error = fo_chown(fp, uap->uid, uap->gid, td->td_ucred, td); @@ -3155,12 +3175,13 @@ kern_utimesat(struct thread *td, int fd, char *path, enum uio_seg pathseg, { struct nameidata nd; struct timespec ts[2]; + cap_rights_t rights; int error; if ((error = getutimes(tptr, tptrseg, ts)) != 0) return (error); NDINIT_ATRIGHTS(&nd, LOOKUP, FOLLOW | AUDITVNODE1, pathseg, path, fd, - CAP_FUTIMES, td); + cap_rights_init(&rights, CAP_FUTIMES), td); if ((error = namei(&nd)) != 0) return (error); @@ -3238,12 +3259,15 @@ kern_futimes(struct thread *td, int fd, struct timeval *tptr, { struct timespec ts[2]; struct file *fp; + cap_rights_t rights; int error; AUDIT_ARG_FD(fd); if ((error = getutimes(tptr, tptrseg, ts)) != 0) return (error); - if ((error = getvnode(td->td_proc->p_fd, fd, CAP_FUTIMES, &fp)) != 0) + error = getvnode(td->td_proc->p_fd, fd, + cap_rights_init(&rights, CAP_FUTIMES), &fp); + if (error != 0) return (error); #ifdef AUDIT vn_lock(fp->f_vnode, LK_SHARED | LK_RETRY); @@ -3390,10 +3414,13 @@ sys_fsync(td, uap) struct vnode *vp; struct mount *mp; struct file *fp; + cap_rights_t rights; int error, lock_flags; AUDIT_ARG_FD(uap->fd); - if ((error = getvnode(td->td_proc->p_fd, uap->fd, CAP_FSYNC, &fp)) != 0) + error = getvnode(td->td_proc->p_fd, uap->fd, + cap_rights_init(&rights, CAP_FSYNC), &fp); + if (error != 0) return (error); vp = fp->f_vnode; if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0) @@ -3472,15 +3499,17 @@ kern_renameat(struct thread *td, int oldfd, char *old, int newfd, char *new, struct mount *mp = NULL; struct vnode *tvp, *fvp, *tdvp; struct nameidata fromnd, tond; + cap_rights_t rights; int error; bwillwrite(); #ifdef MAC NDINIT_ATRIGHTS(&fromnd, DELETE, LOCKPARENT | LOCKLEAF | SAVESTART | - AUDITVNODE1, pathseg, old, oldfd, CAP_RENAMEAT, td); + AUDITVNODE1, pathseg, old, oldfd, + cap_rights_init(&rights, CAP_RENAMEAT), td); #else NDINIT_ATRIGHTS(&fromnd, DELETE, WANTPARENT | SAVESTART | AUDITVNODE1, - pathseg, old, oldfd, CAP_RENAMEAT, td); + pathseg, old, oldfd, cap_rights_init(&rights, CAP_RENAMEAT), td); #endif if ((error = namei(&fromnd)) != 0) @@ -3502,7 +3531,8 @@ kern_renameat(struct thread *td, int oldfd, char *old, int newfd, char *new, goto out1; } NDINIT_ATRIGHTS(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | - SAVESTART | AUDITVNODE2, pathseg, new, newfd, CAP_LINKAT, td); + SAVESTART | AUDITVNODE2, pathseg, new, newfd, + cap_rights_init(&rights, CAP_LINKAT), td); if (fromnd.ni_vp->v_type == VDIR) tond.ni_cnd.cn_flags |= WILLBEDIR; if ((error = namei(&tond)) != 0) { @@ -3531,8 +3561,8 @@ kern_renameat(struct thread *td, int oldfd, char *old, int newfd, char *new, * If the target already exists we require CAP_UNLINKAT * from 'newfd'. */ - error = cap_check(tond.ni_filecaps.fc_rights, - CAP_UNLINKAT); + error = cap_check(&tond.ni_filecaps.fc_rights, + cap_rights_init(&rights, CAP_UNLINKAT)); if (error != 0) goto out; } @@ -3630,6 +3660,7 @@ kern_mkdirat(struct thread *td, int fd, char *path, enum uio_seg segflg, struct mount *mp; struct vnode *vp; struct vattr vattr; + cap_rights_t rights; int error; struct nameidata nd; @@ -3637,7 +3668,7 @@ kern_mkdirat(struct thread *td, int fd, char *path, enum uio_seg segflg, restart: bwillwrite(); NDINIT_ATRIGHTS(&nd, CREATE, LOCKPARENT | SAVENAME | AUDITVNODE1, - segflg, path, fd, CAP_MKDIRAT, td); + segflg, path, fd, cap_rights_init(&rights, CAP_MKDIRAT), td); nd.ni_cnd.cn_flags |= WILLBEDIR; if ((error = namei(&nd)) != 0) return (error); @@ -3715,13 +3746,14 @@ kern_rmdirat(struct thread *td, int fd, char *path, enum uio_seg pathseg) { struct mount *mp; struct vnode *vp; + cap_rights_t rights; int error; struct nameidata nd; restart: bwillwrite(); NDINIT_ATRIGHTS(&nd, DELETE, LOCKPARENT | LOCKLEAF | AUDITVNODE1, - pathseg, path, fd, CAP_UNLINKAT, td); + pathseg, path, fd, cap_rights_init(&rights, CAP_UNLINKAT), td); if ((error = namei(&nd)) != 0) return (error); vp = nd.ni_vp; @@ -3806,6 +3838,7 @@ kern_ogetdirentries(struct thread *td, struct ogetdirentries_args *uap, struct uio auio, kuio; struct iovec aiov, kiov; struct dirent *dp, *edp; + cap_rights_t rights; caddr_t dirbuf; int error, eofflag, readcnt; long loff; @@ -3814,7 +3847,9 @@ kern_ogetdirentries(struct thread *td, struct ogetdirentries_args *uap, /* XXX arbitrary sanity limit on `count'. */ if (uap->count > 64 * 1024) return (EINVAL); - if ((error = getvnode(td->td_proc->p_fd, uap->fd, CAP_READ, &fp)) != 0) + error = getvnode(td->td_proc->p_fd, uap->fd, + cap_rights_init(&rights, CAP_READ), &fp); + if (error != 0) return (error); if ((fp->f_flag & FREAD) == 0) { fdrop(fp, td); @@ -3967,6 +4002,7 @@ kern_getdirentries(struct thread *td, int fd, char *buf, u_int count, struct file *fp; struct uio auio; struct iovec aiov; + cap_rights_t rights; long loff; int error, eofflag; off_t foffset; @@ -3975,7 +4011,9 @@ kern_getdirentries(struct thread *td, int fd, char *buf, u_int count, if (count > IOSIZE_MAX) return (EINVAL); auio.uio_resid = count; - if ((error = getvnode(td->td_proc->p_fd, fd, CAP_READ, &fp)) != 0) + error = getvnode(td->td_proc->p_fd, fd, + cap_rights_init(&rights, CAP_READ), &fp); + if (error != 0) return (error); if ((fp->f_flag & FREAD) == 0) { fdrop(fp, td); @@ -4138,12 +4176,12 @@ out: * entry is held upon returning. */ int -getvnode(struct filedesc *fdp, int fd, cap_rights_t rights, struct file **fpp) +getvnode(struct filedesc *fdp, int fd, cap_rights_t *rightsp, struct file **fpp) { struct file *fp; int error; - error = fget_unlocked(fdp, fd, rights, 0, &fp, NULL); + error = fget_unlocked(fdp, fd, rightsp, 0, &fp, NULL); if (error != 0) return (error); @@ -4466,11 +4504,12 @@ kern_posix_fallocate(struct thread *td, int fd, off_t offset, off_t len) struct file *fp; struct mount *mp; struct vnode *vp; + cap_rights_t rights; off_t olen, ooffset; int error; fp = NULL; - error = fget(td, fd, CAP_WRITE, &fp); + error = fget(td, fd, cap_rights_init(&rights, CAP_WRITE), &fp); if (error != 0) goto out; @@ -4562,6 +4601,7 @@ kern_posix_fadvise(struct thread *td, int fd, off_t offset, off_t len, struct fadvise_info *fa, *new; struct file *fp; struct vnode *vp; + cap_rights_t rights; off_t end; int error; @@ -4582,7 +4622,7 @@ kern_posix_fadvise(struct thread *td, int fd, off_t offset, off_t len, return (EINVAL); } /* XXX: CAP_POSIX_FADVISE? */ - error = fget(td, fd, CAP_NONE, &fp); + error = fget(td, fd, cap_rights_init(&rights), &fp); if (error != 0) goto out; diff --git a/sys/netsmb/smb_dev.c b/sys/netsmb/smb_dev.c index 0efb282ad026..279ae6716e6b 100644 --- a/sys/netsmb/smb_dev.c +++ b/sys/netsmb/smb_dev.c @@ -378,6 +378,7 @@ int smb_dev2share(int fd, int mode, struct smb_cred *scred, struct smb_share **sspp, struct smb_dev **ssdp) { + cap_rights_t rights; struct file *fp, *fptmp; struct smb_dev *sdp; struct smb_share *ssp; @@ -385,7 +386,7 @@ smb_dev2share(int fd, int mode, struct smb_cred *scred, int error; td = curthread; - error = fget(td, fd, CAP_READ, &fp); + error = fget(td, fd, cap_rights_init(&rights, CAP_READ), &fp); if (error) return (error); fptmp = td->td_fpop; diff --git a/sys/nfsserver/nfs_srvkrpc.c b/sys/nfsserver/nfs_srvkrpc.c index db69df95cbc9..85003b7b1be5 100644 --- a/sys/nfsserver/nfs_srvkrpc.c +++ b/sys/nfsserver/nfs_srvkrpc.c @@ -168,6 +168,7 @@ nfssvc_nfsserver(struct thread *td, struct nfssvc_args *uap) struct file *fp; struct nfsd_addsock_args addsockarg; struct nfsd_nfsd_args nfsdarg; + cap_rights_t rights; int error; if (uap->flag & NFSSVC_ADDSOCK) { @@ -175,7 +176,8 @@ nfssvc_nfsserver(struct thread *td, struct nfssvc_args *uap) sizeof(addsockarg)); if (error) return (error); - error = fget(td, addsockarg.sock, CAP_SOCK_SERVER, &fp); + error = fget(td, addsockarg.sock, + cap_rights_init(&rights, CAP_SOCK_SERVER), &fp); if (error) return (error); if (fp->f_type != DTYPE_SOCKET) { diff --git a/sys/security/audit/audit.h b/sys/security/audit/audit.h index dd55875be5b4..559d571cbc45 100644 --- a/sys/security/audit/audit.h +++ b/sys/security/audit/audit.h @@ -114,7 +114,7 @@ void audit_arg_auditon(union auditon_udata *udata); void audit_arg_file(struct proc *p, struct file *fp); void audit_arg_argv(char *argv, int argc, int length); void audit_arg_envv(char *envv, int envc, int length); -void audit_arg_rights(cap_rights_t rights); +void audit_arg_rights(cap_rights_t *rightsp); void audit_arg_fcntl_rights(uint32_t fcntlrights); void audit_sysclose(struct thread *td, int fd); void audit_cred_copy(struct ucred *src, struct ucred *dest); diff --git a/sys/security/audit/audit_arg.c b/sys/security/audit/audit_arg.c index 4927be0d1349..2e86842ba439 100644 --- a/sys/security/audit/audit_arg.c +++ b/sys/security/audit/audit_arg.c @@ -861,7 +861,7 @@ audit_arg_envv(char *envv, int envc, int length) } void -audit_arg_rights(cap_rights_t rights) +audit_arg_rights(cap_rights_t *rightsp) { struct kaudit_record *ar; @@ -869,7 +869,7 @@ audit_arg_rights(cap_rights_t rights) if (ar == NULL) return; - ar->k_ar.ar_arg_rights = rights; + ar->k_ar.ar_arg_rights = *rightsp; ARG_SET_VALID(ar, ARG_RIGHTS); } diff --git a/sys/security/audit/audit_bsm.c b/sys/security/audit/audit_bsm.c index 03b3c23e5c42..9f29eceb3ad0 100644 --- a/sys/security/audit/audit_bsm.c +++ b/sys/security/audit/audit_bsm.c @@ -1611,14 +1611,13 @@ kaudit_to_bsm(struct kaudit_record *kar, struct au_record **pau) } break; - case AUE_CAP_NEW: case AUE_CAP_RIGHTS_LIMIT: /* * XXXRW/XXXJA: Would be nice to audit socket/etc information. */ FD_VNODE1_TOKENS; if (ARG_IS_VALID(kar, ARG_RIGHTS)) { - tok = au_to_arg64(2, "rights", ar->ar_arg_rights); + tok = au_to_rights(&ar->ar_arg_rights); kau_write(rec, tok); } break; diff --git a/sys/security/audit/audit_private.h b/sys/security/audit/audit_private.h index e23ba087ae1d..b5c373ae53ec 100644 --- a/sys/security/audit/audit_private.h +++ b/sys/security/audit/audit_private.h @@ -41,6 +41,7 @@ #error "no user-serviceable parts inside" #endif +#include #include #include #include diff --git a/sys/security/audit/bsm_token.c b/sys/security/audit/bsm_token.c index 6d0d67fcff12..763d59721eb7 100644 --- a/sys/security/audit/bsm_token.c +++ b/sys/security/audit/bsm_token.c @@ -835,6 +835,22 @@ au_to_process_ex(au_id_t auid, uid_t euid, gid_t egid, uid_t ruid, tid)); } +token_t * +au_to_rights(cap_rights_t *rightsp) +{ + token_t *t; + u_char *dptr; + int i; + + GET_TOKEN_AREA(t, dptr, sizeof(u_char) + sizeof(*rightsp)); + + ADD_U_CHAR(dptr, AUT_RIGHTS); + for (i = 0; i < nitems(rightsp->cr_rights); i++) + ADD_U_INT64(dptr, rightsp->cr_rights[i]); + + return (t); +} + /* * token ID 1 byte * error status 1 byte diff --git a/sys/security/mac/mac_syscalls.c b/sys/security/mac/mac_syscalls.c index ff55ec924d3a..64055869767e 100644 --- a/sys/security/mac/mac_syscalls.c +++ b/sys/security/mac/mac_syscalls.c @@ -229,6 +229,7 @@ sys___mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap) struct vnode *vp; struct pipe *pipe; struct socket *so; + cap_rights_t rights; short label_type; int error; @@ -248,7 +249,7 @@ sys___mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap) } buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); - error = fget(td, uap->fd, CAP_MAC_GET, &fp); + error = fget(td, uap->fd, cap_rights_init(&rights, CAP_MAC_GET), &fp); if (error) goto out; @@ -425,6 +426,7 @@ sys___mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap) struct mount *mp; struct vnode *vp; struct mac mac; + cap_rights_t rights; char *buffer; int error; @@ -443,7 +445,7 @@ sys___mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap) return (error); } - error = fget(td, uap->fd, CAP_MAC_SET, &fp); + error = fget(td, uap->fd, cap_rights_init(&rights, CAP_MAC_SET), &fp); if (error) goto out; diff --git a/sys/sys/_types.h b/sys/sys/_types.h index 34d1edbd8eab..ffef9d8b9abc 100644 --- a/sys/sys/_types.h +++ b/sys/sys/_types.h @@ -38,7 +38,6 @@ typedef __uint32_t __blksize_t; /* file block size */ typedef __int64_t __blkcnt_t; /* file block count */ typedef __int32_t __clockid_t; /* clock_gettime()... */ -typedef __uint64_t __cap_rights_t; /* capability rights */ typedef __uint32_t __fflags_t; /* file flags */ typedef __uint64_t __fsblkcnt_t; typedef __uint64_t __fsfilcnt_t; diff --git a/sys/sys/capability.h b/sys/sys/capability.h index ec63de7ff9e3..e5b9ec721c90 100644 --- a/sys/sys/capability.h +++ b/sys/sys/capability.h @@ -42,9 +42,16 @@ #include #include +#include #include #include +#ifndef _KERNEL +#include +#endif + +#define CAPRIGHT(idx, bit) ((1ULL << (57 + (idx))) | (bit)) + /* * Possible rights on capabilities. * @@ -59,29 +66,31 @@ * involve reads or writes depending a great deal on context. */ -#define CAP_NONE 0x0000000000000000ULL +/* INDEX 0 */ /* * General file I/O. */ /* Allows for openat(O_RDONLY), read(2), readv(2). */ -#define CAP_READ 0x0000000000000001ULL +#define CAP_READ CAPRIGHT(0, 0x0000000000000001ULL) /* Allows for openat(O_WRONLY | O_APPEND), write(2), writev(2). */ -#define CAP_WRITE 0x0000000000000002ULL +#define CAP_WRITE CAPRIGHT(0, 0x0000000000000002ULL) +/* Allows for lseek(fd, 0, SEEK_CUR). */ +#define CAP_SEEK_TELL CAPRIGHT(0, 0x0000000000000004ULL) /* Allows for lseek(2). */ -#define CAP_SEEK 0x0000000000000080ULL +#define CAP_SEEK (CAP_SEEK_TELL | 0x0000000000000008ULL) /* Allows for pread(2), preadv(2). */ #define CAP_PREAD (CAP_SEEK | CAP_READ) /* Allows for openat(O_WRONLY) (without O_APPEND), pwrite(2), pwritev(2). */ #define CAP_PWRITE (CAP_SEEK | CAP_WRITE) /* Allows for mmap(PROT_NONE). */ -#define CAP_MMAP 0x0000000000000004ULL +#define CAP_MMAP CAPRIGHT(0, 0x0000000000000010ULL) /* Allows for mmap(PROT_READ). */ #define CAP_MMAP_R (CAP_MMAP | CAP_SEEK | CAP_READ) /* Allows for mmap(PROT_WRITE). */ #define CAP_MMAP_W (CAP_MMAP | CAP_SEEK | CAP_WRITE) /* Allows for mmap(PROT_EXEC). */ -#define CAP_MMAP_X (CAP_MMAP | CAP_SEEK | 0x0000000000000008ULL) +#define CAP_MMAP_X (CAP_MMAP | CAP_SEEK | 0x0000000000000020ULL) /* Allows for mmap(PROT_READ | PROT_WRITE). */ #define CAP_MMAP_RW (CAP_MMAP_R | CAP_MMAP_W) /* Allows for mmap(PROT_READ | PROT_EXEC). */ @@ -91,67 +100,67 @@ /* Allows for mmap(PROT_READ | PROT_WRITE | PROT_EXEC). */ #define CAP_MMAP_RWX (CAP_MMAP_R | CAP_MMAP_W | CAP_MMAP_X) /* Allows for openat(O_CREAT). */ -#define CAP_CREATE 0x0000000000080000ULL +#define CAP_CREATE CAPRIGHT(0, 0x0000000000000040ULL) /* Allows for openat(O_EXEC) and fexecve(2) in turn. */ -#define CAP_FEXECVE 0x0000000000000010ULL +#define CAP_FEXECVE CAPRIGHT(0, 0x0000000000000080ULL) /* Allows for openat(O_SYNC), openat(O_FSYNC), fsync(2). */ -#define CAP_FSYNC 0x0000000000000020ULL +#define CAP_FSYNC CAPRIGHT(0, 0x0000000000000100ULL) /* Allows for openat(O_TRUNC), ftruncate(2). */ -#define CAP_FTRUNCATE 0x0000000000000040ULL - -/* VFS methods. */ -#define CAP_FCHDIR 0x0000000000000200ULL -#define CAP_FCHFLAGS 0x0000000000000100ULL -#define CAP_CHFLAGSAT CAP_FCHFLAGS -#define CAP_FCHMOD 0x0000000000000400ULL -#define CAP_FCHMODAT CAP_FCHMOD -#define CAP_FCHOWN 0x0000000000000800ULL -#define CAP_FCHOWNAT CAP_FCHOWN -#define CAP_FCNTL 0x0000000000001000ULL -#define CAP_FLOCK 0x0000000000004000ULL -#define CAP_FPATHCONF 0x0000000000002000ULL -#define CAP_FSCK 0x0000000000008000ULL -#define CAP_FSTAT 0x0000000000010000ULL -#define CAP_FSTATAT CAP_FSTAT -#define CAP_FSTATFS 0x0000000000020000ULL -#define CAP_FUTIMES 0x0000000000040000ULL -#define CAP_FUTIMESAT CAP_FUTIMES -#define CAP_LINKAT 0x0000000000400000ULL -#define CAP_MKDIRAT 0x0000000000200000ULL -#define CAP_MKFIFOAT 0x0000000000800000ULL -#define CAP_MKNODAT 0x0080000000000000ULL -#define CAP_RENAMEAT 0x0200000000000000ULL -#define CAP_SYMLINKAT 0x0100000000000000ULL -#define CAP_UNLINKAT 0x0000000000100000ULL +#define CAP_FTRUNCATE CAPRIGHT(0, 0x0000000000000200ULL) /* Lookups - used to constrain *at() calls. */ -#define CAP_LOOKUP 0x0000000001000000ULL +#define CAP_LOOKUP CAPRIGHT(0, 0x0000000000000400ULL) + +/* VFS methods. */ +#define CAP_FCHDIR CAPRIGHT(0, 0x0000000000000800ULL) +#define CAP_FCHFLAGS CAPRIGHT(0, 0x0000000000001000ULL) +#define CAP_CHFLAGSAT (CAP_FCHFLAGS | CAP_LOOKUP) +#define CAP_FCHMOD CAPRIGHT(0, 0x0000000000002000ULL) +#define CAP_FCHMODAT (CAP_FCHMOD | CAP_LOOKUP) +#define CAP_FCHOWN CAPRIGHT(0, 0x0000000000004000ULL) +#define CAP_FCHOWNAT (CAP_FCHOWN | CAP_LOOKUP) +#define CAP_FCNTL CAPRIGHT(0, 0x0000000000008000ULL) +#define CAP_FLOCK CAPRIGHT(0, 0x0000000000010000ULL) +#define CAP_FPATHCONF CAPRIGHT(0, 0x0000000000020000ULL) +#define CAP_FSCK CAPRIGHT(0, 0x0000000000040000ULL) +#define CAP_FSTAT CAPRIGHT(0, 0x0000000000080000ULL) +#define CAP_FSTATAT (CAP_FSTAT | CAP_LOOKUP) +#define CAP_FSTATFS CAPRIGHT(0, 0x0000000000100000ULL) +#define CAP_FUTIMES CAPRIGHT(0, 0x0000000000200000ULL) +#define CAP_FUTIMESAT (CAP_FUTIMES | CAP_LOOKUP) +#define CAP_LINKAT CAPRIGHT(0, 0x0000000000400000ULL) +#define CAP_MKDIRAT CAPRIGHT(0, 0x0000000000800000ULL) +#define CAP_MKFIFOAT CAPRIGHT(0, 0x0000000001000000ULL) +#define CAP_MKNODAT CAPRIGHT(0, 0x0000000002000000ULL) +#define CAP_RENAMEAT CAPRIGHT(0, 0x0000000004000000ULL) +#define CAP_SYMLINKAT CAPRIGHT(0, 0x0000000008000000ULL) +#define CAP_UNLINKAT CAPRIGHT(0, 0x0000000010000000ULL) /* Extended attributes. */ -#define CAP_EXTATTR_DELETE 0x0000000002000000ULL -#define CAP_EXTATTR_GET 0x0000000004000000ULL -#define CAP_EXTATTR_LIST 0x0000000008000000ULL -#define CAP_EXTATTR_SET 0x0000000010000000ULL +#define CAP_EXTATTR_DELETE CAPRIGHT(0, 0x0000000020000000ULL) +#define CAP_EXTATTR_GET CAPRIGHT(0, 0x0000000040000000ULL) +#define CAP_EXTATTR_LIST CAPRIGHT(0, 0x0000000080000000ULL) +#define CAP_EXTATTR_SET CAPRIGHT(0, 0x0000000100000000ULL) /* Access Control Lists. */ -#define CAP_ACL_CHECK 0x0000000020000000ULL -#define CAP_ACL_DELETE 0x0000000040000000ULL -#define CAP_ACL_GET 0x0000000080000000ULL -#define CAP_ACL_SET 0x0000000100000000ULL +#define CAP_ACL_CHECK CAPRIGHT(0, 0x0000000200000000ULL) +#define CAP_ACL_DELETE CAPRIGHT(0, 0x0000000400000000ULL) +#define CAP_ACL_GET CAPRIGHT(0, 0x0000000800000000ULL) +#define CAP_ACL_SET CAPRIGHT(0, 0x0000001000000000ULL) /* Socket operations. */ -#define CAP_ACCEPT 0x0000000200000000ULL -#define CAP_BIND 0x0000000400000000ULL -#define CAP_CONNECT 0x0000000800000000ULL -#define CAP_GETPEERNAME 0x0000001000000000ULL -#define CAP_GETSOCKNAME 0x0000002000000000ULL -#define CAP_GETSOCKOPT 0x0000004000000000ULL -#define CAP_LISTEN 0x0000008000000000ULL -#define CAP_PEELOFF 0x0000010000000000ULL +#define CAP_ACCEPT CAPRIGHT(0, 0x0000002000000000ULL) +#define CAP_BIND CAPRIGHT(0, 0x0000004000000000ULL) +#define CAP_CONNECT CAPRIGHT(0, 0x0000008000000000ULL) +#define CAP_GETPEERNAME CAPRIGHT(0, 0x0000010000000000ULL) +#define CAP_GETSOCKNAME CAPRIGHT(0, 0x0000020000000000ULL) +#define CAP_GETSOCKOPT CAPRIGHT(0, 0x0000040000000000ULL) +#define CAP_LISTEN CAPRIGHT(0, 0x0000080000000000ULL) +#define CAP_PEELOFF CAPRIGHT(0, 0x0000100000000000ULL) #define CAP_RECV CAP_READ #define CAP_SEND CAP_WRITE -#define CAP_SETSOCKOPT 0x0000020000000000ULL -#define CAP_SHUTDOWN 0x0000040000000000ULL +#define CAP_SETSOCKOPT CAPRIGHT(0, 0x0000200000000000ULL) +#define CAP_SHUTDOWN CAPRIGHT(0, 0x0000400000000000ULL) #define CAP_SOCK_CLIENT \ (CAP_CONNECT | CAP_GETPEERNAME | CAP_GETSOCKNAME | CAP_GETSOCKOPT | \ @@ -161,56 +170,69 @@ CAP_GETSOCKOPT | CAP_LISTEN | CAP_PEELOFF | CAP_RECV | CAP_SEND | \ CAP_SETSOCKOPT | CAP_SHUTDOWN) +/* All used bits for index 0. */ +#define CAP_ALL0 CAPRIGHT(0, 0x00007FFFFFFFFFFFULL) + +/* Available bits for index 0. */ +#define CAP_UNUSED0_48 CAPRIGHT(0, 0x0000800000000000ULL) +/* ... */ +#define CAP_UNUSED0_57 CAPRIGHT(0, 0x0100000000000000ULL) + +/* INDEX 1 */ + /* Mandatory Access Control. */ -#define CAP_MAC_GET 0x0000080000000000ULL -#define CAP_MAC_SET 0x0000100000000000ULL +#define CAP_MAC_GET CAPRIGHT(1, 0x0000000000000001ULL) +#define CAP_MAC_SET CAPRIGHT(1, 0x0000000000000002ULL) /* Methods on semaphores. */ -#define CAP_SEM_GETVALUE 0x0000200000000000ULL -#define CAP_SEM_POST 0x0000400000000000ULL -#define CAP_SEM_WAIT 0x0000800000000000ULL +#define CAP_SEM_GETVALUE CAPRIGHT(1, 0x0000000000000004ULL) +#define CAP_SEM_POST CAPRIGHT(1, 0x0000000000000008ULL) +#define CAP_SEM_WAIT CAPRIGHT(1, 0x0000000000000010ULL) /* kqueue events. */ -#define CAP_POLL_EVENT 0x0001000000000000ULL -#define CAP_POST_EVENT 0x0002000000000000ULL +#define CAP_POLL_EVENT CAPRIGHT(1, 0x0000000000000020ULL) +#define CAP_POST_EVENT CAPRIGHT(1, 0x0000000000000040ULL) /* Strange and powerful rights that should not be given lightly. */ -#define CAP_IOCTL 0x0004000000000000ULL -#define CAP_TTYHOOK 0x0008000000000000ULL +#define CAP_IOCTL CAPRIGHT(1, 0x0000000000000080ULL) +#define CAP_TTYHOOK CAPRIGHT(1, 0x0000000000000100ULL) /* Process management via process descriptors. */ -#define CAP_PDGETPID 0x0010000000000000ULL -#define CAP_PDWAIT 0x0020000000000000ULL -#define CAP_PDKILL 0x0040000000000000ULL +#define CAP_PDGETPID CAPRIGHT(1, 0x0000000000000200ULL) +#define CAP_PDWAIT CAPRIGHT(1, 0x0000000000000400ULL) +#define CAP_PDKILL CAPRIGHT(1, 0x0000000000000800ULL) /* * Rights that allow to use bindat(2) and connectat(2) syscalls on a * directory descriptor. */ -#define CAP_BINDAT 0x0400000000000000ULL -#define CAP_CONNECTAT 0x0800000000000000ULL - -/* The mask of all valid method rights. */ -#define CAP_MASK_VALID 0x0fffffffffffffffULL -#define CAP_ALL CAP_MASK_VALID - -/* Available bits. */ -#define CAP_UNUSED3 0x1000000000000000ULL -#define CAP_UNUSED2 0x2000000000000000ULL -#define CAP_UNUSED1 0x4000000000000000ULL -#define CAP_UNUSED0 0x8000000000000000ULL - -/* - * The following defines are provided for backward API compatibility and - * should not be used in new code. - */ -#define CAP_MAPEXEC CAP_MMAP_X -#define CAP_DELETE CAP_UNLINKAT -#define CAP_MKDIR CAP_MKDIRAT -#define CAP_RMDIR CAP_UNLINKAT -#define CAP_MKFIFO CAP_MKFIFOAT -#define CAP_MKNOD CAP_MKNODAT -#define CAP_SOCK_ALL (CAP_SOCK_CLIENT | CAP_SOCK_SERVER) +#define CAP_BINDAT CAPRIGHT(1, 0x0000000000001000ULL) +#define CAP_CONNECTAT CAPRIGHT(1, 0x0000000000002000ULL) + +/* All used bits for index 1. */ +#define CAP_ALL1 CAPRIGHT(1, 0x0000000000003FFFULL) + +/* Available bits for index 1. */ +#define CAP_UNUSED1_15 CAPRIGHT(1, 0x0000000000004000ULL) +/* ... */ +#define CAP_UNUSED1_57 CAPRIGHT(1, 0x0100000000000000ULL) + +#define CAP_ALL(rights) do { \ + (rights)->cr_rights[0] = \ + ((uint64_t)CAP_RIGHTS_VERSION << 62) | CAP_ALL0; \ + (rights)->cr_rights[1] = CAP_ALL1; \ +} while (0) + +#define CAP_NONE(rights) do { \ + (rights)->cr_rights[0] = \ + ((uint64_t)CAP_RIGHTS_VERSION << 62) | CAPRIGHT(0, 0ULL); \ + (rights)->cr_rights[1] = CAPRIGHT(1, 0ULL); \ +} while (0) + +#define CAPRVER(right) ((int)((right) >> 62)) +#define CAPVER(rights) CAPRVER((rights)->cr_rights[0]) +#define CAPARSIZE(rights) (CAPVER(rights) + 2) +#define CAPIDXBIT(right) ((int)(((right) >> 57) & 0x1F)) /* * Allowed fcntl(2) commands. @@ -230,6 +252,27 @@ #define CAP_IOCTLS_ALL SSIZE_MAX +#define cap_rights_init(...) \ + __cap_rights_init(CAP_RIGHTS_VERSION, __VA_ARGS__, 0ULL) +cap_rights_t *__cap_rights_init(int version, cap_rights_t *rights, ...); + +#define cap_rights_set(rights, ...) \ + __cap_rights_set((rights), __VA_ARGS__, 0ULL) +void __cap_rights_set(cap_rights_t *rights, ...); + +#define cap_rights_clear(rights, ...) \ + __cap_rights_clear((rights), __VA_ARGS__, 0ULL) +void __cap_rights_clear(cap_rights_t *rights, ...); + +#define cap_rights_is_set(rights, ...) \ + __cap_rights_is_set((rights), __VA_ARGS__, 0ULL) +bool __cap_rights_is_set(const cap_rights_t *rights, ...); + +bool cap_rights_is_valid(const cap_rights_t *rights); +void cap_rights_merge(cap_rights_t *dst, const cap_rights_t *src); +void cap_rights_remove(cap_rights_t *dst, const cap_rights_t *src); +bool cap_rights_contains(const cap_rights_t *big, const cap_rights_t *little); + #ifdef _KERNEL #include @@ -241,17 +284,17 @@ struct filedesc; /* * Test whether a capability grants the requested rights. */ -int cap_check(cap_rights_t have, cap_rights_t need); +int cap_check(const cap_rights_t *havep, const cap_rights_t *needp); /* * Convert capability rights into VM access flags. */ -u_char cap_rights_to_vmprot(cap_rights_t have); +u_char cap_rights_to_vmprot(cap_rights_t *havep); /* * For the purposes of procstat(1) and similar tools, allow kern_descrip.c to * extract the rights from a capability. */ -cap_rights_t cap_rights(struct filedesc *fdp, int fd); +cap_rights_t *cap_rights(struct filedesc *fdp, int fd); int cap_ioctl_check(struct filedesc *fdp, int fd, u_long cmd); int cap_fcntl_check(struct filedesc *fdp, int fd, int cmd); @@ -259,18 +302,11 @@ int cap_fcntl_check(struct filedesc *fdp, int fd, int cmd); #else /* !_KERNEL */ __BEGIN_DECLS -#include - /* * cap_enter(): Cause the process to enter capability mode, which will * prevent it from directly accessing global namespaces. System calls will * be limited to process-local, process-inherited, or file descriptor * operations. If already in capability mode, a no-op. - * - * Currently, process-inherited operations are not properly handled -- in - * particular, we're interested in things like waitpid(2), kill(2), etc, - * being properly constrained. One possible solution is to introduce process - * descriptors. */ int cap_enter(void); @@ -288,11 +324,12 @@ int cap_getmode(u_int *modep); /* * Limits capability rights for the given descriptor (CAP_*). */ -int cap_rights_limit(int fd, cap_rights_t rights); +int cap_rights_limit(int fd, const cap_rights_t *rights); /* - * Returns bitmask of capability rights for the given descriptor. + * Returns capability rights for the given descriptor. */ -int cap_rights_get(int fd, cap_rights_t *rightsp); +#define cap_rights_get(fd, rights) __cap_rights_get(CAP_RIGHTS_VERSION, (fd), (rights)) +int __cap_rights_get(int version, int fd, cap_rights_t *rightsp); /* * Limits allowed ioctls for the given descriptor. */ @@ -312,10 +349,6 @@ int cap_fcntls_limit(int fd, uint32_t fcntlrights); */ int cap_fcntls_get(int fd, uint32_t *fcntlrightsp); -/* For backward compatibility. */ -int cap_new(int fd, cap_rights_t rights); -#define cap_getrights(fd, rightsp) cap_rights_get((fd), (rightsp)) - __END_DECLS #endif /* !_KERNEL */ diff --git a/sys/sys/caprights.h b/sys/sys/caprights.h new file mode 100644 index 000000000000..eb8e454f1de9 --- /dev/null +++ b/sys/sys/caprights.h @@ -0,0 +1,61 @@ +/*- + * Copyright (c) 2013 FreeBSD Foundation + * All rights reserved. + * + * This software was developed by Pawel Jakub Dawidek under sponsorship from + * the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _SYS_CAPRIGHTS_H_ +#define _SYS_CAPRIGHTS_H_ + +/* + * The top two bits in the first element of the cr_rights[] array contain + * total number of elements in the array - 2. This means if those two bits are + * equal to 0, we have 2 array elements. + * The top two bits in all remaining array elements should be 0. + * The next five bits contain array index. Only one bit is used and bit position + * in this five-bits range defines array index. This means there can be at most + * five array elements. + */ +#define CAP_RIGHTS_VERSION_00 0 +/* +#define CAP_RIGHTS_VERSION_01 1 +#define CAP_RIGHTS_VERSION_02 2 +#define CAP_RIGHTS_VERSION_03 3 +*/ +#define CAP_RIGHTS_VERSION CAP_RIGHTS_VERSION_00 + +struct cap_rights { + uint64_t cr_rights[CAP_RIGHTS_VERSION + 2]; +}; + +#ifndef _CAP_RIGHTS_T_DECLARED +#define _CAP_RIGHTS_T_DECLARED +typedef struct cap_rights cap_rights_t; +#endif + +#endif /* !_SYS_CAPRIGHTS_H_ */ diff --git a/sys/sys/file.h b/sys/sys/file.h index 72c512fb8fce..7b373f0d7091 100644 --- a/sys/sys/file.h +++ b/sys/sys/file.h @@ -217,12 +217,12 @@ extern int maxfiles; /* kernel limit on number of open files */ extern int maxfilesperproc; /* per process limit on number of open files */ extern volatile int openfiles; /* actual number of open files */ -int fget(struct thread *td, int fd, cap_rights_t rights, struct file **fpp); -int fget_mmap(struct thread *td, int fd, cap_rights_t rights, +int fget(struct thread *td, int fd, cap_rights_t *rightsp, struct file **fpp); +int fget_mmap(struct thread *td, int fd, cap_rights_t *rightsp, u_char *maxprotp, struct file **fpp); -int fget_read(struct thread *td, int fd, cap_rights_t rights, +int fget_read(struct thread *td, int fd, cap_rights_t *rightsp, struct file **fpp); -int fget_write(struct thread *td, int fd, cap_rights_t rights, +int fget_write(struct thread *td, int fd, cap_rights_t *rightsp, struct file **fpp); int _fdrop(struct file *fp, struct thread *td); @@ -248,17 +248,18 @@ fo_sendfile_t vn_sendfile; fo_seek_t vn_seek; void finit(struct file *, u_int, short, void *, struct fileops *); -int fgetvp(struct thread *td, int fd, cap_rights_t rights, struct vnode **vpp); -int fgetvp_exec(struct thread *td, int fd, cap_rights_t rights, +int fgetvp(struct thread *td, int fd, cap_rights_t *rightsp, struct vnode **vpp); -int fgetvp_rights(struct thread *td, int fd, cap_rights_t need, +int fgetvp_exec(struct thread *td, int fd, cap_rights_t *rightsp, + struct vnode **vpp); +int fgetvp_rights(struct thread *td, int fd, cap_rights_t *needrightsp, struct filecaps *havecaps, struct vnode **vpp); -int fgetvp_read(struct thread *td, int fd, cap_rights_t rights, +int fgetvp_read(struct thread *td, int fd, cap_rights_t *rightsp, struct vnode **vpp); -int fgetvp_write(struct thread *td, int fd, cap_rights_t rights, +int fgetvp_write(struct thread *td, int fd, cap_rights_t *rightsp, struct vnode **vpp); -int fgetsock(struct thread *td, int fd, cap_rights_t rights, +int fgetsock(struct thread *td, int fd, cap_rights_t *rightsp, struct socket **spp, u_int *fflagp); void fputsock(struct socket *sp); diff --git a/sys/sys/filedesc.h b/sys/sys/filedesc.h index 9f73915b8faa..968ceffe9ffa 100644 --- a/sys/sys/filedesc.h +++ b/sys/sys/filedesc.h @@ -33,6 +33,7 @@ #ifndef _SYS_FILEDESC_H_ #define _SYS_FILEDESC_H_ +#include #include #include #include @@ -108,10 +109,6 @@ struct filedesc_to_leader { #ifdef _KERNEL -#include /* CTASSERT() */ - -CTASSERT(sizeof(cap_rights_t) == sizeof(uint64_t)); - /* Flags for do_dup() */ #define DUP_FIXED 0x1 /* Force fixed allocation. */ #define DUP_FCNTL 0x2 /* fcntl()-style errors. */ @@ -163,13 +160,13 @@ struct filedesc *fdshare(struct filedesc *fdp); struct filedesc_to_leader * filedesc_to_leader_alloc(struct filedesc_to_leader *old, struct filedesc *fdp, struct proc *leader); -int getvnode(struct filedesc *fdp, int fd, cap_rights_t rights, +int getvnode(struct filedesc *fdp, int fd, cap_rights_t *rightsp, struct file **fpp); void mountcheckdirs(struct vnode *olddp, struct vnode *newdp); void setugidsafety(struct thread *td); /* Return a referenced file from an unlocked descriptor. */ -int fget_unlocked(struct filedesc *fdp, int fd, cap_rights_t needrights, +int fget_unlocked(struct filedesc *fdp, int fd, cap_rights_t *needrightsp, int needfcntl, struct file **fpp, cap_rights_t *haverightsp); /* Requires a FILEDESC_{S,X}LOCK held and returns without a ref. */ diff --git a/sys/sys/ktrace.h b/sys/sys/ktrace.h index b3e6be8a7fe2..e9cfa6ef5b80 100644 --- a/sys/sys/ktrace.h +++ b/sys/sys/ktrace.h @@ -33,6 +33,8 @@ #ifndef _SYS_KTRACE_H_ #define _SYS_KTRACE_H_ +#include + /* * operations to ktrace system call (KTROP(op)) */ @@ -264,7 +266,10 @@ void ktrprocexit(struct thread *); void ktrprocfork(struct proc *, struct proc *); void ktruserret(struct thread *); void ktrstruct(const char *, void *, size_t); -void ktrcapfail(enum ktr_cap_fail_type, cap_rights_t, cap_rights_t); +void ktrcapfail(enum ktr_cap_fail_type, const cap_rights_t *, + const cap_rights_t *); +#define ktrcaprights(s) \ + ktrstruct("caprights", (s), sizeof(cap_rights_t)) #define ktrsockaddr(s) \ ktrstruct("sockaddr", (s), ((struct sockaddr *)(s))->sa_len) #define ktrstat(s) \ diff --git a/sys/sys/namei.h b/sys/sys/namei.h index a9992f43c68f..f1b1223b6ca5 100644 --- a/sys/sys/namei.h +++ b/sys/sys/namei.h @@ -33,6 +33,7 @@ #ifndef _SYS_NAMEI_H_ #define _SYS_NAMEI_H_ +#include #include #include #include @@ -158,32 +159,14 @@ struct nameidata { NDINIT_ALL(ndp, op, flags, segflg, namep, AT_FDCWD, NULL, 0, td) #define NDINIT_AT(ndp, op, flags, segflg, namep, dirfd, td) \ NDINIT_ALL(ndp, op, flags, segflg, namep, dirfd, NULL, 0, td) -#define NDINIT_ATRIGHTS(ndp, op, flags, segflg, namep, dirfd, rights, td) \ - NDINIT_ALL(ndp, op, flags, segflg, namep, dirfd, NULL, rights, td) +#define NDINIT_ATRIGHTS(ndp, op, flags, segflg, namep, dirfd, rightsp, td) \ + NDINIT_ALL(ndp, op, flags, segflg, namep, dirfd, NULL, rightsp, td) #define NDINIT_ATVP(ndp, op, flags, segflg, namep, vp, td) \ NDINIT_ALL(ndp, op, flags, segflg, namep, AT_FDCWD, vp, 0, td) -static __inline void -NDINIT_ALL(struct nameidata *ndp, - u_long op, u_long flags, - enum uio_seg segflg, - const char *namep, - int dirfd, - struct vnode *startdir, - cap_rights_t rights, - struct thread *td) -{ - ndp->ni_cnd.cn_nameiop = op; - ndp->ni_cnd.cn_flags = flags; - ndp->ni_segflg = segflg; - ndp->ni_dirp = namep; - ndp->ni_dirfd = dirfd; - ndp->ni_startdir = startdir; - ndp->ni_strictrelative = 0; - ndp->ni_rightsneeded = rights; - filecaps_init(&ndp->ni_filecaps); - ndp->ni_cnd.cn_thread = td; -} +void NDINIT_ALL(struct nameidata *ndp, u_long op, u_long flags, + enum uio_seg segflg, const char *namep, int dirfd, struct vnode *startdir, + cap_rights_t *rightsp, struct thread *td); #define NDF_NO_DVP_RELE 0x00000001 #define NDF_NO_DVP_UNLOCK 0x00000002 diff --git a/sys/sys/procdesc.h b/sys/sys/procdesc.h index cc8b7166f639..4d77a0564033 100644 --- a/sys/sys/procdesc.h +++ b/sys/sys/procdesc.h @@ -92,8 +92,8 @@ struct procdesc { * In-kernel interfaces to process descriptors. */ int procdesc_exit(struct proc *); -int procdesc_find(struct thread *, int fd, cap_rights_t, struct proc **); -int kern_pdgetpid(struct thread *, int fd, cap_rights_t, pid_t *pidp); +int procdesc_find(struct thread *, int fd, cap_rights_t *, struct proc **); +int kern_pdgetpid(struct thread *, int fd, cap_rights_t *, pid_t *pidp); void procdesc_new(struct proc *, int); void procdesc_finit(struct procdesc *, struct file *); pid_t procdesc_pid(struct file *); diff --git a/sys/sys/types.h b/sys/sys/types.h index cc0bca8f33bd..03eaa6002ef6 100644 --- a/sys/sys/types.h +++ b/sys/sys/types.h @@ -88,8 +88,6 @@ typedef __blkcnt_t blkcnt_t; #define _BLKCNT_T_DECLARED #endif -typedef __cap_rights_t cap_rights_t; - #ifndef _CLOCK_T_DECLARED typedef __clock_t clock_t; #define _CLOCK_T_DECLARED @@ -234,6 +232,13 @@ typedef __useconds_t useconds_t; /* microseconds (unsigned) */ #define _USECONDS_T_DECLARED #endif +#ifndef _CAP_RIGHTS_T_DECLARED +#define _CAP_RIGHTS_T_DECLARED +struct cap_rights; + +typedef struct cap_rights cap_rights_t; +#endif + typedef __vm_offset_t vm_offset_t; typedef __vm_ooffset_t vm_ooffset_t; typedef __vm_paddr_t vm_paddr_t; diff --git a/sys/sys/user.h b/sys/sys/user.h index 9389e55e0b08..349003d73daf 100644 --- a/sys/sys/user.h +++ b/sys/sys/user.h @@ -61,6 +61,7 @@ #ifndef _SYS_SOCKET_VAR_H_ #include #endif +#include /* * KERN_PROC subtype ops return arrays of selected proc structure entries: @@ -318,7 +319,7 @@ struct kinfo_ofile { }; #if defined(__amd64__) || defined(__i386__) -#define KINFO_FILE_SIZE 1392 +#define KINFO_FILE_SIZE 1424 #endif struct kinfo_file { @@ -389,6 +390,7 @@ struct kinfo_file { uint16_t kf_pad1; /* Round to 32 bit alignment. */ int _kf_ispare0; /* Space for more stuff. */ cap_rights_t kf_cap_rights; /* Capability rights. */ + uint64_t _kf_cap_spare[3]; /* Space for future cap_rights_t. */ int _kf_ispare[4]; /* Space for more stuff. */ /* Truncated before copyout in sysctl */ char kf_path[PATH_MAX]; /* Path to file, if any. */ diff --git a/sys/ufs/ffs/ffs_alloc.c b/sys/ufs/ffs/ffs_alloc.c index 3063adeb5bd1..19e880c63541 100644 --- a/sys/ufs/ffs/ffs_alloc.c +++ b/sys/ufs/ffs/ffs_alloc.c @@ -2709,6 +2709,7 @@ sysctl_ffs_fsck(SYSCTL_HANDLER_ARGS) long blkcnt, blksize; struct filedesc *fdp; struct file *fp, *vfp; + cap_rights_t rights; int filetype, error; static struct fileops *origops, bufferedops; @@ -2718,8 +2719,8 @@ sysctl_ffs_fsck(SYSCTL_HANDLER_ARGS) return (error); if (cmd.version != FFS_CMD_VERSION) return (ERPCMISMATCH); - if ((error = getvnode(td->td_proc->p_fd, cmd.handle, CAP_FSCK, - &fp)) != 0) + if ((error = getvnode(td->td_proc->p_fd, cmd.handle, + cap_rights_init(&rights, CAP_FSCK), &fp)) != 0) return (error); vp = fp->f_data; if (vp->v_type != VREG && vp->v_type != VDIR) { @@ -3033,7 +3034,7 @@ sysctl_ffs_fsck(SYSCTL_HANDLER_ARGS) } #endif /* DEBUG */ if ((error = getvnode(td->td_proc->p_fd, cmd.value, - CAP_FSCK, &vfp)) != 0) + cap_rights_init(&rights, CAP_FSCK), &vfp)) != 0) break; if (vfp->f_vnode->v_type != VCHR) { fdrop(vfp, td); diff --git a/sys/vm/vm_mmap.c b/sys/vm/vm_mmap.c index 53a7be51d7f7..77f64f4e9b79 100644 --- a/sys/vm/vm_mmap.c +++ b/sys/vm/vm_mmap.c @@ -311,17 +311,17 @@ sys_mmap(td, uap) * rights, but also return the maximum rights to be combined * with maxprot later. */ - rights = CAP_MMAP; + cap_rights_init(&rights, CAP_MMAP); if (prot & PROT_READ) - rights |= CAP_MMAP_R; + cap_rights_set(&rights, CAP_MMAP_R); if ((flags & MAP_SHARED) != 0) { if (prot & PROT_WRITE) - rights |= CAP_MMAP_W; + cap_rights_set(&rights, CAP_MMAP_W); } if (prot & PROT_EXEC) - rights |= CAP_MMAP_X; - if ((error = fget_mmap(td, uap->fd, rights, &cap_maxprot, - &fp)) != 0) + cap_rights_set(&rights, CAP_MMAP_X); + error = fget_mmap(td, uap->fd, &rights, &cap_maxprot, &fp); + if (error != 0) goto done; if (fp->f_type == DTYPE_SHM) { handle = fp->f_data; diff --git a/usr.bin/kdump/kdump.c b/usr.bin/kdump/kdump.c index 06be0c0a482e..0de183c1a224 100644 --- a/usr.bin/kdump/kdump.c +++ b/usr.bin/kdump/kdump.c @@ -103,6 +103,7 @@ void ktrcsw_old(struct ktr_csw_old *); void ktruser_malloc(unsigned char *); void ktruser_rtld(int, unsigned char *); void ktruser(int, unsigned char *); +void ktrcaprights(cap_rights_t *); void ktrsockaddr(struct sockaddr *); void ktrstat(struct stat *); void ktrstruct(char *, size_t); @@ -379,21 +380,21 @@ limitfd(int fd) cap_rights_t rights; unsigned long cmd; - rights = CAP_FSTAT; + cap_rights_init(&rights, CAP_FSTAT); cmd = -1; switch (fd) { case STDIN_FILENO: - rights |= CAP_READ; + cap_rights_set(&rights, CAP_READ); break; case STDOUT_FILENO: - rights |= CAP_IOCTL | CAP_WRITE; + cap_rights_set(&rights, CAP_IOCTL, CAP_WRITE); cmd = TIOCGETA; /* required by isatty(3) in printf(3) */ break; case STDERR_FILENO: - rights |= CAP_WRITE; + cap_rights_set(&rights, CAP_WRITE); if (!suppressdata) { - rights |= CAP_IOCTL; + cap_rights_set(&rights, CAP_IOCTL); cmd = TIOCGWINSZ; } break; @@ -401,7 +402,7 @@ limitfd(int fd) abort(); } - if (cap_rights_limit(fd, rights) < 0 && errno != ENOSYS) + if (cap_rights_limit(fd, &rights) < 0 && errno != ENOSYS) err(1, "unable to limit rights for descriptor %d", fd); if (cmd != -1 && cap_ioctls_limit(fd, &cmd, 1) < 0 && errno != ENOSYS) err(1, "unable to limit ioctls for descriptor %d", fd); @@ -1120,35 +1121,6 @@ ktrsyscall(struct ktr_syscall *ktr, u_int flags) ip++; narg--; break; - case SYS_cap_new: - case SYS_cap_rights_limit: - print_number(ip, narg, c); - putchar(','); - arg = *ip; - ip++; - narg--; - /* - * Hack: the second argument is a - * cap_rights_t, which 64 bits wide, so on - * 32-bit systems, it is split between two - * registers. - * - * Since sizeof() is not evaluated by the - * preprocessor, we can't use an #ifdef, - * but the compiler will probably optimize - * the code out anyway. - */ - if (sizeof(cap_rights_t) > sizeof(register_t)) { -#if _BYTE_ORDER == _LITTLE_ENDIAN - arg = ((intmax_t)*ip << 32) + arg; -#else - arg = (arg << 32) + *ip; -#endif - ip++; - narg--; - } - capname(arg); - break; case SYS_cap_fcntls_limit: print_number(ip, narg, c); putchar(','); @@ -1535,6 +1507,15 @@ ktruser(int len, unsigned char *p) printf("\n"); } +void +ktrcaprights(cap_rights_t *rightsp) +{ + + printf("cap_rights_t "); + capname(rightsp); + printf("\n"); +} + void ktrsockaddr(struct sockaddr *sa) { @@ -1712,6 +1693,7 @@ ktrstruct(char *buf, size_t buflen) char *name, *data; size_t namelen, datalen; int i; + cap_rights_t rights; struct stat sb; struct sockaddr_storage ss; @@ -1731,7 +1713,12 @@ ktrstruct(char *buf, size_t buflen) for (i = 0; i < (int)namelen; ++i) if (!isalpha(name[i])) goto invalid; - if (strcmp(name, "stat") == 0) { + if (strcmp(name, "caprights") == 0) { + if (datalen != sizeof(cap_rights_t)) + goto invalid; + memcpy(&rights, data, datalen); + ktrcaprights(&rights); + } else if (strcmp(name, "stat") == 0) { if (datalen != sizeof(struct stat)) goto invalid; memcpy(&sb, data, datalen); @@ -1758,16 +1745,16 @@ ktrcapfail(struct ktr_cap_fail *ktr) case CAPFAIL_NOTCAPABLE: /* operation on fd with insufficient capabilities */ printf("operation requires "); - capname((intmax_t)ktr->cap_needed); + capname(&ktr->cap_needed); printf(", process holds "); - capname((intmax_t)ktr->cap_held); + capname(&ktr->cap_held); break; case CAPFAIL_INCREASE: /* requested more capabilities than fd already has */ printf("attempt to increase capabilities from "); - capname((intmax_t)ktr->cap_held); + capname(&ktr->cap_held); printf(" to "); - capname((intmax_t)ktr->cap_needed); + capname(&ktr->cap_needed); break; case CAPFAIL_SYSCALL: /* called restricted syscall */ @@ -1779,9 +1766,9 @@ ktrcapfail(struct ktr_cap_fail *ktr) break; default: printf("unknown capability failure: "); - capname((intmax_t)ktr->cap_needed); + capname(&ktr->cap_needed); printf(" "); - capname((intmax_t)ktr->cap_held); + capname(&ktr->cap_held); break; } printf("\n"); diff --git a/usr.bin/kdump/mksubr b/usr.bin/kdump/mksubr index b10af9426010..676e9e223f5e 100644 --- a/usr.bin/kdump/mksubr +++ b/usr.bin/kdump/mksubr @@ -385,7 +385,6 @@ _EOF_ auto_or_type "accessmodename" "[A-Z]_OK[[:space:]]+0?x?[0-9A-Fa-f]+" "sys/unistd.h" auto_switch_type "acltypename" "ACL_TYPE_[A-Z4_]+[[:space:]]+0x[0-9]+" "sys/acl.h" -auto_or_type "capname" "CAP_[A-Z]+[[:space:]]+0x[01248]{16}ULL" "sys/capability.h" auto_or_type "capfcntlname" "CAP_FCNTL_[A-Z]+[[:space:]]+\(1" "sys/capability.h" auto_switch_type "extattrctlname" "EXTATTR_NAMESPACE_[A-Z]+[[:space:]]+0x[0-9]+" "sys/extattr.h" auto_switch_type "fadvisebehavname" "POSIX_FADV_[A-Z]+[[:space:]]+[0-9]+" "sys/fcntl.h" @@ -609,3 +608,26 @@ cat <<_EOF_ } } } + +_EOF_ +egrep '#define[[:space:]]+CAP_[A-Z_]+[[:space:]]+CAPRIGHT\([0-9],[[:space:]]+0x[0-9]{16}ULL\)' \ + $include_dir/sys/capability.h | \ + sed -E 's/[ ]+/ /g' | \ + awk -F '[ \(,\)]' ' + BEGIN { + printf "void\n" + printf "capname(const cap_rights_t *rightsp)\n" + printf "{\n" + printf "\tint comma = 0;\n\n" + printf "\tprintf(\"<\");\n" + } + { + printf "\tif ((rightsp->cr_rights[%s] & %s) == %s) {\n", $4, $2, $2 + printf "\t\tif (comma) printf(\",\"); else comma = 1;\n" + printf "\t\tprintf(\"%s\");\n", $2 + printf "\t}\n" + } + END { + printf "\tprintf(\">\");\n" + printf "}\n" + }' diff --git a/usr.bin/procstat/procstat_files.c b/usr.bin/procstat/procstat_files.c index 72600de0bb62..d65c1ae93982 100644 --- a/usr.bin/procstat/procstat_files.c +++ b/usr.bin/procstat/procstat_files.c @@ -133,7 +133,7 @@ print_address(struct sockaddr_storage *ss) } static struct cap_desc { - cap_rights_t cd_right; + uint64_t cd_right; const char *cd_desc; } cap_desc[] = { /* General file I/O. */ @@ -244,14 +244,14 @@ static const u_int cap_desc_count = sizeof(cap_desc) / sizeof(cap_desc[0]); static u_int -width_capability(cap_rights_t rights) +width_capability(cap_rights_t *rightsp) { u_int count, i, width; count = 0; width = 0; for (i = 0; i < cap_desc_count; i++) { - if ((cap_desc[i].cd_right & ~rights) == 0) { + if (cap_rights_is_set(rightsp, cap_desc[i].cd_right)) { width += strlen(cap_desc[i].cd_desc); if (count) width++; @@ -262,20 +262,20 @@ width_capability(cap_rights_t rights) } static void -print_capability(cap_rights_t rights, u_int capwidth) +print_capability(cap_rights_t *rightsp, u_int capwidth) { u_int count, i, width; count = 0; width = 0; - for (i = width_capability(rights); i < capwidth; i++) { - if (rights || i != 0) + for (i = width_capability(rightsp); i < capwidth; i++) { + if (i != 0) printf(" "); else printf("-"); } for (i = 0; i < cap_desc_count; i++) { - if ((cap_desc[i].cd_right & ~rights) == 0) { + if (cap_rights_is_set(rightsp, cap_desc[i].cd_right)) { printf("%s%s", count ? "," : "", cap_desc[i].cd_desc); width += strlen(cap_desc[i].cd_desc); if (count) @@ -306,7 +306,7 @@ procstat_files(struct procstat *procstat, struct kinfo_proc *kipp) head = procstat_getfiles(procstat, kipp, 0); if (head != NULL && Cflag) { STAILQ_FOREACH(fst, head, next) { - width = width_capability(fst->fs_cap_rights); + width = width_capability(&fst->fs_cap_rights); if (width > capwidth) capwidth = width; } @@ -460,7 +460,7 @@ procstat_files(struct procstat *procstat, struct kinfo_proc *kipp) printf("%7c ", '-'); } if (Cflag) { - print_capability(fst->fs_cap_rights, capwidth); + print_capability(&fst->fs_cap_rights, capwidth); printf(" "); } switch (fst->fs_type) { diff --git a/usr.bin/rwho/rwho.c b/usr.bin/rwho/rwho.c index bcb5adb8e919..8c985f0170d1 100644 --- a/usr.bin/rwho/rwho.c +++ b/usr.bin/rwho/rwho.c @@ -93,6 +93,7 @@ main(int argc, char *argv[]) struct whod *w; struct whoent *we; struct myutmp *mp; + cap_rights_t rights; int f, n, i; int d_first; int dfd; @@ -124,7 +125,8 @@ main(int argc, char *argv[]) err(1, "opendir(%s)", _PATH_RWHODIR); dfd = dirfd(dirp); mp = myutmp; - if (cap_rights_limit(dfd, CAP_READ | CAP_LOOKUP) < 0 && errno != ENOSYS) + cap_rights_init(&rights, CAP_READ, CAP_LOOKUP); + if (cap_rights_limit(dfd, &rights) < 0 && errno != ENOSYS) err(1, "cap_rights_limit failed: %s", _PATH_RWHODIR); /* * Cache files required for time(3) and localtime(3) before entering @@ -135,13 +137,14 @@ main(int argc, char *argv[]) if (cap_enter() < 0 && errno != ENOSYS) err(1, "cap_enter"); (void) time(&now); + cap_rights_init(&rights, CAP_READ); while ((dp = readdir(dirp)) != NULL) { if (dp->d_ino == 0 || strncmp(dp->d_name, "whod.", 5) != 0) continue; f = openat(dfd, dp->d_name, O_RDONLY); if (f < 0) continue; - if (cap_rights_limit(f, CAP_READ) < 0 && errno != ENOSYS) + if (cap_rights_limit(f, &rights) < 0 && errno != ENOSYS) err(1, "cap_rights_limit failed: %s", dp->d_name); cc = read(f, (char *)&wd, sizeof(struct whod)); if (cc < WHDRSIZE) { diff --git a/usr.bin/uniq/uniq.c b/usr.bin/uniq/uniq.c index d34b0c0a5b37..8e7f40fd14c4 100644 --- a/usr.bin/uniq/uniq.c +++ b/usr.bin/uniq/uniq.c @@ -145,20 +145,19 @@ main (int argc, char *argv[]) ofp = stdout; if (argc > 0 && strcmp(argv[0], "-") != 0) ifp = file(ifn = argv[0], "r"); - if (cap_rights_limit(fileno(ifp), CAP_FSTAT | CAP_READ) < 0 && - errno != ENOSYS) { + cap_rights_init(&rights, CAP_FSTAT, CAP_READ); + if (cap_rights_limit(fileno(ifp), &rights) < 0 && errno != ENOSYS) err(1, "unable to limit rights for %s", ifn); - } - rights = CAP_FSTAT | CAP_WRITE; + cap_rights_init(&rights, CAP_FSTAT, CAP_WRITE); if (argc > 1) ofp = file(argv[1], "w"); else - rights |= CAP_IOCTL; - if (cap_rights_limit(fileno(ofp), rights) < 0 && errno != ENOSYS) { + cap_rights_set(&rights, CAP_IOCTL); + if (cap_rights_limit(fileno(ofp), &rights) < 0 && errno != ENOSYS) { err(1, "unable to limit rights for %s", argc > 1 ? argv[1] : "stdout"); } - if ((rights & CAP_IOCTL) != 0) { + if (cap_rights_is_set(&rights, CAP_IOCTL)) { unsigned long cmd; cmd = TIOCGETA; /* required by isatty(3) in printf(3) */ diff --git a/usr.sbin/rwhod/rwhod.c b/usr.sbin/rwhod/rwhod.c index 25b86928757b..5dc6079593d7 100644 --- a/usr.sbin/rwhod/rwhod.c +++ b/usr.sbin/rwhod/rwhod.c @@ -354,6 +354,7 @@ receiver_process(void) { struct sockaddr_in from; struct stat st; + cap_rights_t rights; char path[64]; int dirfd; struct whod wd; @@ -367,8 +368,9 @@ receiver_process(void) syslog(LOG_WARNING, "%s: %m", _PATH_RWHODIR); exit(1); } - if (cap_rights_limit(dirfd, CAP_CREATE | CAP_WRITE | CAP_FTRUNCATE | - CAP_SEEK | CAP_LOOKUP | CAP_FSTAT) < 0 && errno != ENOSYS) { + cap_rights_init(&rights, CAP_CREATE, CAP_FSTAT, CAP_FTRUNCATE, + CAP_LOOKUP, CAP_SEEK, CAP_WRITE); + if (cap_rights_limit(dirfd, &rights) < 0 && errno != ENOSYS) { syslog(LOG_WARNING, "cap_rights_limit: %m"); exit(1); } @@ -413,8 +415,8 @@ receiver_process(void) syslog(LOG_WARNING, "%s: %m", path); continue; } - if (cap_rights_limit(whod, CAP_WRITE | CAP_FTRUNCATE | - CAP_FSTAT) < 0 && errno != ENOSYS) { + cap_rights_init(&rights, CAP_FSTAT, CAP_FTRUNCATE, CAP_WRITE); + if (cap_rights_limit(whod, &rights) < 0 && errno != ENOSYS) { syslog(LOG_WARNING, "cap_rights_limit: %m"); exit(1); } -- cgit v1.3