summaryrefslogtreecommitdiffstats
path: root/sys/kern/uipc_usrreq.c
diff options
context:
space:
mode:
authorpjd <pjd@FreeBSD.org>2013-03-02 00:53:12 +0000
committerpjd <pjd@FreeBSD.org>2013-03-02 00:53:12 +0000
commitf07ebb8888ea42f744890a727e8f6799a1086915 (patch)
tree90495ae13fcc0dd621d97fc1b788f43780023c0a /sys/kern/uipc_usrreq.c
parentdd15932a159ec60641cd20e4fb689fa28d75465d (diff)
downloadFreeBSD-src-f07ebb8888ea42f744890a727e8f6799a1086915.zip
FreeBSD-src-f07ebb8888ea42f744890a727e8f6799a1086915.tar.gz
Merge Capsicum overhaul:
- Capability is no longer separate descriptor type. Now every descriptor has set of its own capability rights. - The cap_new(2) system call is left, but it is no longer documented and should not be used in new code. - The new syscall cap_rights_limit(2) should be used instead of cap_new(2), which limits capability rights of the given descriptor without creating a new one. - The cap_getrights(2) syscall is renamed to cap_rights_get(2). - If CAP_IOCTL capability right is present we can further reduce allowed ioctls list with the new cap_ioctls_limit(2) syscall. List of allowed ioctls can be retrived with cap_ioctls_get(2) syscall. - If CAP_FCNTL capability right is present we can further reduce fcntls that can be used with the new cap_fcntls_limit(2) syscall and retrive them with cap_fcntls_get(2). - To support ioctl and fcntl white-listing the filedesc structure was heavly modified. - The audit subsystem, kdump and procstat tools were updated to recognize new syscalls. - Capability rights were revised and eventhough I tried hard to provide backward API and ABI compatibility there are some incompatible changes that are described in detail below: CAP_CREATE old behaviour: - Allow for openat(2)+O_CREAT. - Allow for linkat(2). - Allow for symlinkat(2). CAP_CREATE new behaviour: - Allow for openat(2)+O_CREAT. Added CAP_LINKAT: - Allow for linkat(2). ABI: Reuses CAP_RMDIR bit. - Allow to be target for renameat(2). Added CAP_SYMLINKAT: - Allow for symlinkat(2). Removed CAP_DELETE. Old behaviour: - Allow for unlinkat(2) when removing non-directory object. - Allow to be source for renameat(2). Removed CAP_RMDIR. Old behaviour: - Allow for unlinkat(2) when removing directory. Added CAP_RENAMEAT: - Required for source directory for the renameat(2) syscall. Added CAP_UNLINKAT (effectively it replaces CAP_DELETE and CAP_RMDIR): - Allow for unlinkat(2) on any object. - Required if target of renameat(2) exists and will be removed by this call. Removed CAP_MAPEXEC. CAP_MMAP old behaviour: - Allow for mmap(2) with any combination of PROT_NONE, PROT_READ and PROT_WRITE. CAP_MMAP new behaviour: - Allow for mmap(2)+PROT_NONE. Added CAP_MMAP_R: - Allow for mmap(PROT_READ). Added CAP_MMAP_W: - Allow for mmap(PROT_WRITE). Added CAP_MMAP_X: - Allow for mmap(PROT_EXEC). Added CAP_MMAP_RW: - Allow for mmap(PROT_READ | PROT_WRITE). Added CAP_MMAP_RX: - Allow for mmap(PROT_READ | PROT_EXEC). Added CAP_MMAP_WX: - Allow for mmap(PROT_WRITE | PROT_EXEC). Added CAP_MMAP_RWX: - Allow for mmap(PROT_READ | PROT_WRITE | PROT_EXEC). Renamed CAP_MKDIR to CAP_MKDIRAT. Renamed CAP_MKFIFO to CAP_MKFIFOAT. Renamed CAP_MKNODE to CAP_MKNODEAT. CAP_READ old behaviour: - Allow pread(2). - Disallow read(2), readv(2) (if there is no CAP_SEEK). CAP_READ new behaviour: - Allow read(2), readv(2). - Disallow pread(2) (CAP_SEEK was also required). CAP_WRITE old behaviour: - Allow pwrite(2). - Disallow write(2), writev(2) (if there is no CAP_SEEK). CAP_WRITE new behaviour: - Allow write(2), writev(2). - Disallow pwrite(2) (CAP_SEEK was also required). Added convinient defines: #define CAP_PREAD (CAP_SEEK | CAP_READ) #define CAP_PWRITE (CAP_SEEK | CAP_WRITE) #define CAP_MMAP_R (CAP_MMAP | CAP_SEEK | CAP_READ) #define CAP_MMAP_W (CAP_MMAP | CAP_SEEK | CAP_WRITE) #define CAP_MMAP_X (CAP_MMAP | CAP_SEEK | 0x0000000000000008ULL) #define CAP_MMAP_RW (CAP_MMAP_R | CAP_MMAP_W) #define CAP_MMAP_RX (CAP_MMAP_R | CAP_MMAP_X) #define CAP_MMAP_WX (CAP_MMAP_W | CAP_MMAP_X) #define CAP_MMAP_RWX (CAP_MMAP_R | CAP_MMAP_W | CAP_MMAP_X) #define CAP_RECV CAP_READ #define CAP_SEND CAP_WRITE #define CAP_SOCK_CLIENT \ (CAP_CONNECT | CAP_GETPEERNAME | CAP_GETSOCKNAME | CAP_GETSOCKOPT | \ CAP_PEELOFF | CAP_RECV | CAP_SEND | CAP_SETSOCKOPT | CAP_SHUTDOWN) #define CAP_SOCK_SERVER \ (CAP_ACCEPT | CAP_BIND | CAP_GETPEERNAME | CAP_GETSOCKNAME | \ CAP_GETSOCKOPT | CAP_LISTEN | CAP_PEELOFF | CAP_RECV | CAP_SEND | \ CAP_SETSOCKOPT | CAP_SHUTDOWN) Added defines for backward API compatibility: #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) Sponsored by: The FreeBSD Foundation Reviewed by: Christoph Mallon <christoph.mallon@gmx.de> Many aspects discussed with: rwatson, benl, jonathan ABI compatibility discussed with: kib
Diffstat (limited to 'sys/kern/uipc_usrreq.c')
-rw-r--r--sys/kern/uipc_usrreq.c89
1 files changed, 45 insertions, 44 deletions
diff --git a/sys/kern/uipc_usrreq.c b/sys/kern/uipc_usrreq.c
index a6c308f..dcfd009 100644
--- a/sys/kern/uipc_usrreq.c
+++ b/sys/kern/uipc_usrreq.c
@@ -279,7 +279,7 @@ static void unp_drop(struct unpcb *, int);
static void unp_gc(__unused void *, int);
static void unp_scan(struct mbuf *, void (*)(struct file *));
static void unp_discard(struct file *);
-static void unp_freerights(struct file **, int);
+static void unp_freerights(struct filedescent *, int);
static void unp_init(void);
static int unp_internalize(struct mbuf **, struct thread *);
static void unp_internalize_fp(struct file *);
@@ -1642,14 +1642,14 @@ unp_drop(struct unpcb *unp, int errno)
}
static void
-unp_freerights(struct file **rp, int fdcount)
+unp_freerights(struct filedescent *fde, int fdcount)
{
- int i;
struct file *fp;
+ int i;
- for (i = 0; i < fdcount; i++) {
- fp = *rp;
- *rp++ = NULL;
+ for (i = 0; i < fdcount; i++, fde++) {
+ fp = fde->fde_file;
+ bzero(fde, sizeof(*fde));
unp_discard(fp);
}
}
@@ -1661,8 +1661,8 @@ unp_externalize(struct mbuf *control, struct mbuf **controlp)
struct cmsghdr *cm = mtod(control, struct cmsghdr *);
int i;
int *fdp;
- struct file **rp;
- struct file *fp;
+ struct filedesc *fdesc = td->td_proc->p_fd;
+ struct filedescent *fde, *fdep;
void *data;
socklen_t clen = control->m_len, datalen;
int error, newfds;
@@ -1683,20 +1683,20 @@ unp_externalize(struct mbuf *control, struct mbuf **controlp)
datalen = (caddr_t)cm + cm->cmsg_len - (caddr_t)data;
if (cm->cmsg_level == SOL_SOCKET
&& cm->cmsg_type == SCM_RIGHTS) {
- newfds = datalen / sizeof(struct file *);
- rp = data;
+ newfds = datalen / sizeof(*fdep);
+ fdep = data;
/* If we're not outputting the descriptors free them. */
if (error || controlp == NULL) {
- unp_freerights(rp, newfds);
+ unp_freerights(fdep, newfds);
goto next;
}
- FILEDESC_XLOCK(td->td_proc->p_fd);
+ FILEDESC_XLOCK(fdesc);
/* if the new FD's will not fit free them. */
if (!fdavail(td, newfds)) {
- FILEDESC_XUNLOCK(td->td_proc->p_fd);
+ FILEDESC_XUNLOCK(fdesc);
error = EMSGSIZE;
- unp_freerights(rp, newfds);
+ unp_freerights(fdep, newfds);
goto next;
}
@@ -1710,23 +1710,24 @@ unp_externalize(struct mbuf *control, struct mbuf **controlp)
*controlp = sbcreatecontrol(NULL, newlen,
SCM_RIGHTS, SOL_SOCKET);
if (*controlp == NULL) {
- FILEDESC_XUNLOCK(td->td_proc->p_fd);
+ FILEDESC_XUNLOCK(fdesc);
error = E2BIG;
- unp_freerights(rp, newfds);
+ unp_freerights(fdep, newfds);
goto next;
}
fdp = (int *)
CMSG_DATA(mtod(*controlp, struct cmsghdr *));
- for (i = 0; i < newfds; i++) {
+ for (i = 0; i < newfds; i++, fdep++, fdp++) {
if (fdalloc(td, 0, &f))
panic("unp_externalize fdalloc failed");
- fp = *rp++;
- td->td_proc->p_fd->fd_ofiles[f] = fp;
- unp_externalize_fp(fp);
- *fdp++ = f;
+ fde = &fdesc->fd_ofiles[f];
+ fde->fde_file = fdep->fde_file;
+ filecaps_copy(&fdep->fde_caps, &fde->fde_caps);
+ unp_externalize_fp(fde->fde_file);
+ *fdp = f;
}
- FILEDESC_XUNLOCK(td->td_proc->p_fd);
+ FILEDESC_XUNLOCK(fdesc);
} else {
/* We can just copy anything else across. */
if (error || controlp == NULL)
@@ -1797,11 +1798,11 @@ unp_internalize(struct mbuf **controlp, struct thread *td)
{
struct mbuf *control = *controlp;
struct proc *p = td->td_proc;
- struct filedesc *fdescp = p->p_fd;
+ struct filedesc *fdesc = p->p_fd;
struct bintime *bt;
struct cmsghdr *cm = mtod(control, struct cmsghdr *);
struct cmsgcred *cmcred;
- struct file **rp;
+ struct filedescent *fde, *fdep;
struct file *fp;
struct timeval *tv;
int i, fd, *fdp;
@@ -1854,18 +1855,17 @@ unp_internalize(struct mbuf **controlp, struct thread *td)
* files. If not, reject the entire operation.
*/
fdp = data;
- FILEDESC_SLOCK(fdescp);
+ FILEDESC_SLOCK(fdesc);
for (i = 0; i < oldfds; i++) {
fd = *fdp++;
- if (fd < 0 || fd >= fdescp->fd_nfiles ||
- fdescp->fd_ofiles[fd] == NULL) {
- FILEDESC_SUNLOCK(fdescp);
+ if (fget_locked(fdesc, fd) == NULL) {
+ FILEDESC_SUNLOCK(fdesc);
error = EBADF;
goto out;
}
- fp = fdescp->fd_ofiles[fd];
+ fp = fdesc->fd_ofiles[fd].fde_file;
if (!(fp->f_ops->fo_flags & DFLAG_PASSABLE)) {
- FILEDESC_SUNLOCK(fdescp);
+ FILEDESC_SUNLOCK(fdesc);
error = EOPNOTSUPP;
goto out;
}
@@ -1874,25 +1874,26 @@ unp_internalize(struct mbuf **controlp, struct thread *td)
/*
* Now replace the integer FDs with pointers to the
- * associated global file table entry..
+ * file structure and capability rights.
*/
- newlen = oldfds * sizeof(struct file *);
+ newlen = oldfds * sizeof(*fdep);
*controlp = sbcreatecontrol(NULL, newlen,
SCM_RIGHTS, SOL_SOCKET);
if (*controlp == NULL) {
- FILEDESC_SUNLOCK(fdescp);
+ FILEDESC_SUNLOCK(fdesc);
error = E2BIG;
goto out;
}
fdp = data;
- rp = (struct file **)
+ fdep = (struct filedescent *)
CMSG_DATA(mtod(*controlp, struct cmsghdr *));
- for (i = 0; i < oldfds; i++) {
- fp = fdescp->fd_ofiles[*fdp++];
- *rp++ = fp;
- unp_internalize_fp(fp);
+ for (i = 0; i < oldfds; i++, fdep++, fdp++) {
+ fde = &fdesc->fd_ofiles[*fdp];
+ fdep->fde_file = fde->fde_file;
+ filecaps_copy(&fde->fde_caps, &fdep->fde_caps);
+ unp_internalize_fp(fdep->fde_file);
}
- FILEDESC_SUNLOCK(fdescp);
+ FILEDESC_SUNLOCK(fdesc);
break;
case SCM_TIMESTAMP:
@@ -2252,7 +2253,7 @@ static void
unp_scan(struct mbuf *m0, void (*op)(struct file *))
{
struct mbuf *m;
- struct file **rp;
+ struct filedescent *fdep;
struct cmsghdr *cm;
void *data;
int i;
@@ -2277,10 +2278,10 @@ unp_scan(struct mbuf *m0, void (*op)(struct file *))
if (cm->cmsg_level == SOL_SOCKET &&
cm->cmsg_type == SCM_RIGHTS) {
- qfds = datalen / sizeof (struct file *);
- rp = data;
- for (i = 0; i < qfds; i++)
- (*op)(*rp++);
+ qfds = datalen / sizeof(*fdep);
+ fdep = data;
+ for (i = 0; i < qfds; i++, fdep++)
+ (*op)(fdep->fde_file);
}
if (CMSG_SPACE(datalen) < clen) {
OpenPOWER on IntegriCloud