PERFORCE change 133789 for review
Robert Watson
rwatson at FreeBSD.org
Mon Jan 21 08:19:03 PST 2008
http://perforce.freebsd.org/chv.cgi?CH=133789
Change 133789 by rwatson at rwatson_freebsd_capabilities on 2008/01/21 16:18:42
Implement capability checks for many common socket system calls.
Affected files ...
.. //depot/projects/trustedbsd/capabilities/src/sys/kern/uipc_syscalls.c#2 edit
Differences ...
==== //depot/projects/trustedbsd/capabilities/src/sys/kern/uipc_syscalls.c#2 (text+ko) ====
@@ -36,11 +36,13 @@
__FBSDID("$FreeBSD: src/sys/kern/uipc_syscalls.c,v 1.263 2008/01/13 14:44:09 attilio Exp $");
#include "opt_sctp.h"
+#include "opt_capabilities.h"
#include "opt_compat.h"
#include "opt_ktrace.h"
#include "opt_mac.h"
#include <sys/param.h>
+#include <sys/capability.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/lock.h>
@@ -106,6 +108,7 @@
SYSCTL_INT(_kern_ipc, OID_AUTO, nsfbufsused, CTLFLAG_RD, &nsfbufsused, 0,
"Number of sendfile(2) sf_bufs in use");
+#if 0
/*
* Convert a user file descriptor to a kernel file entry. A reference on the
* file entry is held upon returning. This is lighter weight than
@@ -142,8 +145,60 @@
*fpp = fp;
return (error);
}
+#endif
/*
+ * Convert a user file descriptor to a kernel file entry and check that, if
+ * it is a capability, the right rights are present. A reference on the file
+ * entry is held upon returning.
+ */
+static int
+getsock_cap(struct filedesc *fdp, int fd, cap_rights_t rights,
+ struct file **fpp, u_int *fflagp)
+{
+ struct file *fp;
+ int error;
+
+ fp = NULL;
+ if (fdp == NULL) {
+ *fpp = NULL;
+ return (EBADF);
+ }
+ FILEDESC_SLOCK(fdp);
+ fp = fget_locked(fdp, fd);
+ if (fp == NULL) {
+ error = EBADF;
+ goto out;
+ }
+
+ /*
+ * If the file descriptor is for a capability, test rights and use
+ * the file descriptor referenced by the capability.
+ */
+#ifdef CAPABILITIES
+ if (fp->f_type == DTYPE_CAPABILITY) {
+ error = cap_fget(fp, rights, &fp);
+ if (error) {
+ fp = NULL;
+ goto out;
+ }
+ }
+#endif /* CAPABILITIES */
+ if (fp->f_vnode == NULL) {
+ error = EINVAL;
+ fp = NULL;
+ goto out;
+ } else {
+ fhold(fp);
+ error = 0;
+ }
+out:
+ FILEDESC_SUNLOCK(fdp);
+ *fpp = fp;
+ return (error);
+}
+
+/*
* System call interface to the socket abstraction.
*/
#if defined(COMPAT_43)
@@ -218,7 +273,7 @@
struct file *fp;
int error;
- error = getsock(td->td_proc->p_fd, fd, &fp, NULL);
+ error = getsock_cap(td->td_proc->p_fd, fd, CAP_BIND, &fp, NULL);
if (error)
return (error);
so = fp->f_data;
@@ -250,7 +305,8 @@
struct file *fp;
int error;
- error = getsock(td->td_proc->p_fd, uap->s, &fp, NULL);
+ error = getsock_cap(td->td_proc->p_fd, uap->s, CAP_LISTEN, &fp,
+ NULL);
if (error == 0) {
so = fp->f_data;
#ifdef MAC
@@ -345,7 +401,7 @@
}
fdp = td->td_proc->p_fd;
- error = getsock(fdp, s, &headfp, &fflag);
+ error = getsock_cap(fdp, s, CAP_ACCEPT, &headfp, &fflag);
if (error)
return (error);
head = headfp->f_data;
@@ -530,7 +586,7 @@
int error;
int interrupted = 0;
- error = getsock(td->td_proc->p_fd, fd, &fp, NULL);
+ error = getsock_cap(td->td_proc->p_fd, fd, CAP_CONNECT, &fp, NULL);
if (error)
return (error);
so = fp->f_data;
@@ -732,11 +788,15 @@
struct socket *so;
int i;
int len, error;
+ cap_rights_t rights;
#ifdef KTRACE
struct uio *ktruio = NULL;
#endif
- error = getsock(td->td_proc->p_fd, s, &fp, NULL);
+ rights = CAP_WRITE;
+ if (mp->msg_name != NULL)
+ rights |= CAP_CONNECT;
+ error = getsock_cap(td->td_proc->p_fd, s, rights, &fp, NULL);
if (error)
return (error);
so = (struct socket *)fp->f_data;
@@ -931,7 +991,7 @@
if(controlp != NULL)
*controlp = 0;
- error = getsock(td->td_proc->p_fd, s, &fp, NULL);
+ error = getsock_cap(td->td_proc->p_fd, s, CAP_READ, &fp, NULL);
if (error)
return (error);
so = fp->f_data;
@@ -1242,7 +1302,8 @@
struct file *fp;
int error;
- error = getsock(td->td_proc->p_fd, uap->s, &fp, NULL);
+ error = getsock_cap(td->td_proc->p_fd, uap->s, CAP_SHUTDOWN, &fp,
+ NULL);
if (error == 0) {
so = fp->f_data;
error = soshutdown(so, uap->how);
@@ -1304,7 +1365,7 @@
panic("kern_setsockopt called with bad valseg");
}
- error = getsock(td->td_proc->p_fd, s, &fp, NULL);
+ error = getsock_cap(td->td_proc->p_fd, s, CAP_SHUTDOWN, &fp, NULL);
if (error == 0) {
so = fp->f_data;
error = sosetopt(so, &sopt);
@@ -1382,7 +1443,7 @@
panic("kern_getsockopt called with bad valseg");
}
- error = getsock(td->td_proc->p_fd, s, &fp, NULL);
+ error = getsock_cap(td->td_proc->p_fd, s, CAP_GETSOCKOPT, &fp, NULL);
if (error == 0) {
so = fp->f_data;
error = sogetopt(so, &sopt);
@@ -1443,7 +1504,8 @@
if (*alen < 0)
return (EINVAL);
- error = getsock(td->td_proc->p_fd, fd, &fp, NULL);
+ error = getsock_cap(td->td_proc->p_fd, fd, CAP_GETSOCKNAME, &fp,
+ NULL);
if (error)
return (error);
so = fp->f_data;
@@ -1536,7 +1598,8 @@
if (*alen < 0)
return (EINVAL);
- error = getsock(td->td_proc->p_fd, fd, &fp, NULL);
+ error = getsock_cap(td->td_proc->p_fd, fd, CAP_GETPEERNAME, &fp,
+ NULL);
if (error)
return (error);
so = fp->f_data;
@@ -1809,8 +1872,8 @@
* The socket must be a stream socket and connected.
* Remember if it a blocking or non-blocking socket.
*/
- if ((error = getsock(td->td_proc->p_fd, uap->s, &sock_fp,
- NULL)) != 0)
+ if ((error = getsock_cap(td->td_proc->p_fd, uap->s, CAP_WRITE,
+ &sock_fp, NULL)) != 0)
goto out;
so = sock_fp->f_data;
if (so->so_type != SOCK_STREAM) {
@@ -2306,6 +2369,7 @@
#endif
struct uio auio;
struct iovec iov[1];
+ cap_rights_t rights;
if (uap->sinfo) {
error = copyin(uap->sinfo, &sinfo, sizeof (sinfo));
@@ -2313,15 +2377,19 @@
return (error);
u_sinfo = &sinfo;
}
+
+ rights = CAP_WRITE;
if (uap->tolen) {
error = getsockaddr(&to, uap->to, uap->tolen);
if (error) {
to = NULL;
goto sctp_bad2;
}
+ rights |= CAP_CONNECT;
}
- error = getsock(td->td_proc->p_fd, uap->sd, &fp, NULL);
+ /* XXXRW: Is this use of rights right for SCTP? */
+ error = getsock_cap(td->td_proc->p_fd, uap->sd, rights, &fp, NULL);
if (error)
goto sctp_bad;
@@ -2405,6 +2473,7 @@
#endif
struct uio auio;
struct iovec *iov, *tiov;
+ cap_rights_t rights;
if (uap->sinfo) {
error = copyin(uap->sinfo, &sinfo, sizeof (sinfo));
@@ -2412,15 +2481,17 @@
return (error);
u_sinfo = &sinfo;
}
+ rights = CAP_WRITE;
if (uap->tolen) {
error = getsockaddr(&to, uap->to, uap->tolen);
if (error) {
to = NULL;
goto sctp_bad2;
}
+ rights |= CAP_CONNECT;
}
- error = getsock(td->td_proc->p_fd, uap->sd, &fp, NULL);
+ error = getsock_cap(td->td_proc->p_fd, uap->sd, rights, &fp, NULL);
if (error)
goto sctp_bad1;
@@ -2516,7 +2587,7 @@
#ifdef KTRACE
struct uio *ktruio = NULL;
#endif
- error = getsock(td->td_proc->p_fd, uap->sd, &fp, NULL);
+ error = getsock_cap(td->td_proc->p_fd, uap->sd, CAP_READ, &fp, NULL);
if (error) {
return (error);
}
More information about the p4-projects
mailing list