* System call switch table.
*
* DO NOT EDIT-- this file is automatically generated.
- * $DragonFly: src/sys/kern/init_sysent.c,v 1.15 2004/01/20 18:41:51 dillon Exp $
- * created from DragonFly: src/sys/kern/syscalls.master,v 1.10 2004/01/18 12:31:08 dillon Exp
+ * $DragonFly: src/sys/kern/init_sysent.c,v 1.16 2004/03/06 22:14:09 dillon Exp $
+ * created from DragonFly: src/sys/kern/syscalls.master,v 1.11 2004/01/20 18:41:51 dillon Exp
*/
#include "opt_compat.h"
{ AS(caps_sys_get_args), (sy_call_t *)caps_sys_get }, /* 460 = caps_sys_get */
{ AS(caps_sys_wait_args), (sy_call_t *)caps_sys_wait }, /* 461 = caps_sys_wait */
{ AS(caps_sys_abort_args), (sy_call_t *)caps_sys_abort }, /* 462 = caps_sys_abort */
- { 0, (sy_call_t *)nosys }, /* 463 = nosys */
- { 0, (sy_call_t *)nosys }, /* 464 = nosys */
+ { AS(caps_sys_getgen_args), (sy_call_t *)caps_sys_getgen }, /* 463 = caps_sys_getgen */
+ { AS(caps_sys_setgen_args), (sy_call_t *)caps_sys_setgen }, /* 464 = caps_sys_setgen */
{ AS(exec_sys_register_args), (sy_call_t *)exec_sys_register }, /* 465 = exec_sys_register */
{ AS(exec_sys_unregister_args), (sy_call_t *)exec_sys_unregister }, /* 466 = exec_sys_unregister */
};
*
* @(#)kern_fork.c 8.6 (Berkeley) 4/8/94
* $FreeBSD: src/sys/kern/kern_fork.c,v 1.72.2.14 2003/06/26 04:15:10 silby Exp $
- * $DragonFly: src/sys/kern/kern_fork.c,v 1.18 2004/02/10 15:31:47 hmp Exp $
+ * $DragonFly: src/sys/kern/kern_fork.c,v 1.19 2004/03/06 22:14:09 dillon Exp $
*/
#include "opt_ktrace.h"
#include <sys/ktrace.h>
#include <sys/unistd.h>
#include <sys/jail.h>
+#include <sys/caps.h>
#include <vm/vm.h>
#include <sys/lock.h>
* execution path later. (ie: directly into user mode)
*/
vm_fork(p1, p2, flags);
+ caps_fork(p1, p2, flags);
if (flags == (RFFDG | RFPROC)) {
mycpu->gd_cnt.v_forks++;
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $DragonFly: src/sys/kern/lwkt_caps.c,v 1.1 2004/01/18 12:29:49 dillon Exp $
+ * $DragonFly: src/sys/kern/lwkt_caps.c,v 1.2 2004/03/06 22:14:09 dillon Exp $
*/
/*
static int caps_process_msg(caps_kinfo_t caps, caps_kmsg_t msg, struct caps_sys_get_args *uap);
static void caps_free(caps_kinfo_t caps);
static void caps_free_msg(caps_kmsg_t msg);
+static int caps_name_check(const char *name, int len);
static caps_kinfo_t caps_free_msg_mcaps(caps_kmsg_t msg);
static caps_kinfo_t kern_caps_sys_service(const char *name, uid_t uid,
gid_t gid, struct ucred *cred,
#define CAPS_HMASK (CAPS_HSIZE - 1)
static caps_kinfo_t caps_hash_ary[CAPS_HSIZE];
+static int caps_waitsvc;
MALLOC_DEFINE(M_CAPS, "caps", "caps IPC messaging");
static
caps_kinfo_t
-caps_find_id(int id)
+caps_find_id(thread_t td, int id)
{
- thread_t td = curthread;
caps_kinfo_t caps;
for (caps = td->td_caps; caps; caps = caps->ci_tdnext) {
static
caps_kinfo_t
-caps_alloc(const char *name, int len, uid_t uid, gid_t gid,
+caps_alloc(thread_t td, const char *name, int len, uid_t uid, gid_t gid,
int flags, caps_type_t type)
{
struct caps_kinfo **chash;
- thread_t td = curthread;
caps_kinfo_t caps;
caps_kinfo_t ctmp;
* It is virtually impossible for this case to occur.
*/
caps->ci_id = 1;
- while ((ctmp = caps_find_id(caps->ci_id)) != NULL) {
+ while ((ctmp = caps_find_id(td, caps->ci_id)) != NULL) {
caps_drop(ctmp);
++caps->ci_id;
}
}
/*
+ * Validate the service name
+ */
+static int
+caps_name_check(const char *name, int len)
+{
+ int i;
+ char c;
+
+ for (i = len - 1; i >= 0; --i) {
+ c = name[i];
+ if (c >= '0' && c <= '9')
+ continue;
+ if (c >= 'a' && c <= 'z')
+ continue;
+ if (c >= 'A' && c <= 'Z')
+ continue;
+ if (c == '_' || c == '.')
+ continue;
+ return(EINVAL);
+ }
+ return(0);
+}
+
+/*
* caps_term()
*
* Terminate portions of a caps info structure. This is used to close
* PROCESS SUPPORT FUNCTIONS *
************************************************************************/
+/*
+ * Create dummy entries in p2 so we can return the appropriate
+ * error code. Robust userland code will check the error for a
+ * forked condition and reforge the connection.
+ */
void
-caps_fork(struct proc *p1, struct proc *p2)
+caps_fork(struct proc *p1, struct proc *p2, int flags)
{
- /* create dummy caps entries that fail? Or dup client entries? XXX */
+ caps_kinfo_t caps1;
+ caps_kinfo_t caps2;
+ thread_t td1;
+ thread_t td2;
+
+ td1 = p1->p_thread;
+ td2 = p2->p_thread;
+
+ /*
+ * Create dummy entries with the same id's as the originals. Note
+ * that service entries are not re-added to the hash table. The
+ * dummy entries return an ENOTCONN error allowing userland code to
+ * detect that a fork occured. Userland must reconnect to the service.
+ */
+ for (caps1 = td1->td_caps; caps1; caps1 = caps1->ci_tdnext) {
+ if (caps1->ci_flags & CAPF_NOFORK)
+ continue;
+ caps2 = caps_alloc(td2,
+ caps1->ci_name, caps1->ci_namelen,
+ caps1->ci_uid, caps1->ci_gid,
+ caps1->ci_flags & CAPF_UFLAGS, CAPT_FORKED);
+ caps2->ci_id = caps1->ci_id;
+ }
+
+ /*
+ * Reverse the list order to maintain highest-id-first
+ */
+ caps2 = td2->td_caps;
+ td2->td_caps = NULL;
+ while (caps2) {
+ caps1 = caps2->ci_tdnext;
+ caps2->ci_tdnext = td2->td_caps;
+ td2->td_caps = caps2;
+ caps2 = caps1;
+ }
}
void
return(error);
if (--len <= 0)
return(EINVAL);
+ if ((error = caps_name_check(name, len)) != 0)
+ return(error);
caps = kern_caps_sys_service(name, uap->uid, uap->gid, cred,
uap->flags & CAPF_UFLAGS, &error);
return(error);
if (--len <= 0)
return(EINVAL);
+ if ((error = caps_name_check(name, len)) != 0)
+ return(error);
caps = kern_caps_sys_client(name, uap->uid, uap->gid, cred,
uap->flags & CAPF_UFLAGS, &error);
{
caps_kinfo_t caps;
- if ((caps = caps_find_id(uap->portid)) == NULL)
+ if ((caps = caps_find_id(curthread, uap->portid)) == NULL)
return(EINVAL);
caps_term(caps, CAPKF_TDLIST|CAPKF_HLIST|CAPKF_FLUSH|CAPKF_RCAPS, NULL);
caps_drop(caps);
return(0);
}
+int
+caps_sys_setgen(struct caps_sys_setgen_args *uap)
+{
+ caps_kinfo_t caps;
+
+ if ((caps = caps_find_id(curthread, uap->portid)) == NULL)
+ return(EINVAL);
+ if (caps->ci_type == CAPT_FORKED)
+ return(ENOTCONN);
+ caps->ci_gen = uap->gen;
+ return(0);
+}
+
+int
+caps_sys_getgen(struct caps_sys_getgen_args *uap)
+{
+ caps_kinfo_t caps;
+
+ if ((caps = caps_find_id(curthread, uap->portid)) == NULL)
+ return(EINVAL);
+ if (caps->ci_type == CAPT_FORKED)
+ return(ENOTCONN);
+ if (caps->ci_rcaps == NULL)
+ return(EINVAL);
+ uap->sysmsg_result64 = caps->ci_rcaps->ci_gen;
+ return(0);
+}
+
/*
* caps_sys_put(portid, msg, msgsize)
*
caps_kinfo_t caps;
caps_kmsg_t msg;
struct proc *p = curproc;
+ int error;
if (uap->msgsize < 0)
return(EINVAL);
- if ((caps = caps_find_id(uap->portid)) == NULL)
+ if ((caps = caps_find_id(curthread, uap->portid)) == NULL)
return(EINVAL);
+ if (caps->ci_type == CAPT_FORKED)
+ return(ENOTCONN);
if (caps->ci_rcaps == NULL) {
caps_drop(caps);
return(EINVAL);
uap->sysmsg_offset = msg->km_msgid.c_id;
/*
- * If the remote end is closed reply the message immediately, otherwise
- * send it to the remote end. Disposal XXX
+ * If the remote end is closed return ENOTCONN immediately, otherwise
+ * send it to the remote end.
*
* Note: since this is a new message, caps_load_ccr() returns a remote
* caps of NULL.
*/
+ error = 0;
if (caps->ci_rcaps->ci_flags & CAPKF_CLOSED) {
+ error = ENOTCONN;
+ caps_free_msg(msg);
+#if 0
caps_load_ccr(caps, msg, p, NULL, 0); /* returns NULL */
caps_hold(caps);
caps_put_msg(caps, msg, CAPMS_REPLY); /* drops caps */
+#endif
} else {
caps_load_ccr(caps, msg, p, uap->msg, uap->msgsize); /* returns NULL */
caps_hold(caps->ci_rcaps); /* need ref */
caps_put_msg(caps->ci_rcaps, msg, CAPMS_REQUEST); /* drops rcaps */
}
caps_drop(caps);
- return(0);
+ return(error);
}
/*
if (uap->msgsize < 0)
return(EINVAL);
- if ((caps = caps_find_id(uap->portid)) == NULL)
+ if ((caps = caps_find_id(curthread, uap->portid)) == NULL)
return(EINVAL);
+ if (caps->ci_type == CAPT_FORKED)
+ return(ENOTCONN);
/*
* Can't find message to reply to
if (uap->maxsize < 0)
return(EINVAL);
- if ((caps = caps_find_id(uap->portid)) == NULL)
+ if ((caps = caps_find_id(curthread, uap->portid)) == NULL)
return(EINVAL);
+ if (caps->ci_type == CAPT_FORKED)
+ return(ENOTCONN);
if ((msg = TAILQ_FIRST(&caps->ci_msgpendq)) == NULL) {
caps_drop(caps);
return(EWOULDBLOCK);
if (uap->maxsize < 0)
return(EINVAL);
- if ((caps = caps_find_id(uap->portid)) == NULL)
+ if ((caps = caps_find_id(curthread, uap->portid)) == NULL)
return(EINVAL);
+ if (caps->ci_type == CAPT_FORKED)
+ return(ENOTCONN);
while ((msg = TAILQ_FIRST(&caps->ci_msgpendq)) == NULL) {
if ((error = tsleep(caps, PCATCH, "caps", 0)) != 0) {
caps_drop(caps);
/*
* Create the service
*/
- caps = caps_alloc(name, len, uid, gid, flags & CAPF_UFLAGS, CAPT_SERVICE);
+ caps = caps_alloc(curthread, name, len,
+ uid, gid, flags & CAPF_UFLAGS, CAPT_SERVICE);
+ wakeup(&caps_waitsvc);
return(caps);
}
/*
* Locate the CAPS service (rcaps ref is for caps->ci_rcaps)
*/
+again:
if ((rcaps = caps_find(name, len, uid, gid)) == NULL) {
- *error = ENOENT;
+ if (flags & CAPF_WAITSVC) {
+ char cbuf[32];
+ snprintf(cbuf, sizeof(cbuf), "C%s", name);
+ *error = tsleep(&caps_waitsvc, PCATCH, cbuf, 0);
+ if (*error == 0)
+ goto again;
+ } else {
+ *error = ENOENT;
+ }
return(NULL);
}
/*
* Allocate the client side and connect to the server
*/
- caps = caps_alloc(name, len, uid, gid, flags & CAPF_UFLAGS, CAPT_CLIENT);
+ caps = caps_alloc(curthread, name, len,
+ uid, gid, flags & CAPF_UFLAGS, CAPT_CLIENT);
caps->ci_rcaps = rcaps;
caps->ci_flags |= CAPKF_RCAPS;
return(caps);
* System call names.
*
* DO NOT EDIT-- this file is automatically generated.
- * $DragonFly: src/sys/kern/syscalls.c,v 1.15 2004/01/20 18:41:51 dillon Exp $
- * created from DragonFly: src/sys/kern/syscalls.master,v 1.10 2004/01/18 12:31:08 dillon Exp
+ * $DragonFly: src/sys/kern/syscalls.c,v 1.16 2004/03/06 22:14:09 dillon Exp $
+ * created from DragonFly: src/sys/kern/syscalls.master,v 1.11 2004/01/20 18:41:51 dillon Exp
*/
char *syscallnames[] = {
"caps_sys_get", /* 460 = caps_sys_get */
"caps_sys_wait", /* 461 = caps_sys_wait */
"caps_sys_abort", /* 462 = caps_sys_abort */
- "#463", /* 463 = nosys */
- "#464", /* 464 = nosys */
+ "caps_sys_getgen", /* 463 = caps_sys_getgen */
+ "caps_sys_setgen", /* 464 = caps_sys_setgen */
"exec_sys_register", /* 465 = exec_sys_register */
"exec_sys_unregister", /* 466 = exec_sys_unregister */
};
- $DragonFly: src/sys/kern/syscalls.master,v 1.11 2004/01/20 18:41:51 dillon Exp $
+ $DragonFly: src/sys/kern/syscalls.master,v 1.12 2004/03/06 22:14:09 dillon Exp $
; @(#)syscalls.master 8.2 (Berkeley) 1/13/94
; $FreeBSD: src/sys/kern/syscalls.master,v 1.72.2.10 2002/07/12 08:22:46 alfred Exp $
460 STD BSD { int caps_sys_get(int portid, void *msg, int maxsize, struct caps_msgid *msgid, struct caps_cred *ccr); }
461 STD BSD { int caps_sys_wait(int portid, void *msg, int maxsize, struct caps_msgid *msgid, struct caps_cred *ccr); }
462 STD BSD { int caps_sys_abort(int portid, off_t msgcid, int flags); }
-463 UNIMPL NOHIDE nosys
-464 UNIMPL NOHIDE nosys
+463 STD BSD { off_t caps_sys_getgen(int portid); }
+464 STD BSD { int caps_sys_setgen(int portid, off_t gen); }
465 STD BSD { int exec_sys_register(void *entry); }
466 STD BSD { int exec_sys_unregister(int id); }
*
* Implements an architecture independant Capability Service API
*
- * $DragonFly: src/sys/sys/caps.h,v 1.4 2004/02/25 17:38:51 joerg Exp $
+ * $DragonFly: src/sys/sys/caps.h,v 1.5 2004/03/06 22:14:16 dillon Exp $
*/
#ifndef _SYS_CAPS_H_
} *caps_msgid_t;
typedef enum caps_type {
- CAPT_UNKNOWN, CAPT_CLIENT, CAPT_SERVICE, CAPT_REMOTE
+ CAPT_UNKNOWN, CAPT_CLIENT, CAPT_SERVICE, CAPT_REMOTE, CAPT_FORKED
} caps_type_t;
+typedef int64_t caps_gen_t;
+
/*
* Note: upper 16 bits reserved for kernel use
*/
#define CAPF_EXCL 0x0008
#define CAPF_ANYCLIENT (CAPF_USER|CAPF_GROUP|CAPF_WORLD)
#define CAPF_WCRED 0x0010 /* waiting for cred */
+#define CAPF_NOFORK 0x0020 /* do not create a dummy entry on fork */
+#define CAPF_WAITSVC 0x0040 /* block if service not available */
/* FUTURE: CAPF_ASYNC - support async services */
/* FUTURE: CAPF_NOGROUPS - don't bother filling in the groups[] array */
/* FUTURE: CAPF_TERM - send termination request to existing service */
int ci_refs;
int ci_mrefs; /* message (vmspace) refs */
caps_type_t ci_type;
+ caps_gen_t ci_gen;
uid_t ci_uid;
gid_t ci_gid;
int ci_namelen;
* kernel support
*/
void caps_exit(struct thread *td);
-void caps_fork(struct proc *p1, struct proc *p2);
+void caps_fork(struct proc *p1, struct proc *p2, int flags);
#else
int caps_sys_get(int, void *, int, caps_msgid_t, caps_cred_t);
int caps_sys_wait(int, void *, int, caps_msgid_t, caps_cred_t);
int caps_sys_abort(int, off_t, int);
+int caps_sys_setgen(int, caps_gen_t);
+caps_gen_t caps_sys_getgen(int);
#endif
* System call hiders.
*
* DO NOT EDIT-- this file is automatically generated.
- * $DragonFly: src/sys/sys/syscall-hide.h,v 1.16 2004/01/20 18:41:51 dillon Exp $
- * created from DragonFly: src/sys/kern/syscalls.master,v 1.10 2004/01/18 12:31:08 dillon Exp
+ * $DragonFly: src/sys/sys/syscall-hide.h,v 1.17 2004/03/06 22:14:16 dillon Exp $
+ * created from DragonFly: src/sys/kern/syscalls.master,v 1.11 2004/01/20 18:41:51 dillon Exp
*/
HIDE_POSIX(fork)
HIDE_BSD(caps_sys_get)
HIDE_BSD(caps_sys_wait)
HIDE_BSD(caps_sys_abort)
+HIDE_BSD(caps_sys_getgen)
+HIDE_BSD(caps_sys_setgen)
HIDE_BSD(exec_sys_register)
HIDE_BSD(exec_sys_unregister)
* System call numbers.
*
* DO NOT EDIT-- this file is automatically generated.
- * $DragonFly: src/sys/sys/syscall.h,v 1.16 2004/01/20 18:41:51 dillon Exp $
- * created from DragonFly: src/sys/kern/syscalls.master,v 1.10 2004/01/18 12:31:08 dillon Exp
+ * $DragonFly: src/sys/sys/syscall.h,v 1.17 2004/03/06 22:14:16 dillon Exp $
+ * created from DragonFly: src/sys/kern/syscalls.master,v 1.11 2004/01/20 18:41:51 dillon Exp
*/
#define SYS_syscall 0
#define SYS_caps_sys_get 460
#define SYS_caps_sys_wait 461
#define SYS_caps_sys_abort 462
+#define SYS_caps_sys_getgen 463
+#define SYS_caps_sys_setgen 464
#define SYS_exec_sys_register 465
#define SYS_exec_sys_unregister 466
#define SYS_MAXSYSCALL 467
# DragonFly system call names.
# DO NOT EDIT-- this file is automatically generated.
-# $DragonFly: src/sys/sys/syscall.mk,v 1.16 2004/01/20 18:41:51 dillon Exp $
-# created from DragonFly: src/sys/kern/syscalls.master,v 1.10 2004/01/18 12:31:08 dillon Exp
+# $DragonFly: src/sys/sys/syscall.mk,v 1.17 2004/03/06 22:14:16 dillon Exp $
+# created from DragonFly: src/sys/kern/syscalls.master,v 1.11 2004/01/20 18:41:51 dillon Exp
MIASM = \
syscall.o \
exit.o \
caps_sys_get.o \
caps_sys_wait.o \
caps_sys_abort.o \
+ caps_sys_getgen.o \
+ caps_sys_setgen.o \
exec_sys_register.o \
exec_sys_unregister.o
* System call prototypes.
*
* DO NOT EDIT-- this file is automatically generated.
- * $DragonFly: src/sys/sys/sysproto.h,v 1.16 2004/01/20 18:41:51 dillon Exp $
- * created from DragonFly: src/sys/kern/syscalls.master,v 1.10 2004/01/18 12:31:08 dillon Exp
+ * $DragonFly: src/sys/sys/sysproto.h,v 1.17 2004/03/06 22:14:16 dillon Exp $
+ * created from DragonFly: src/sys/kern/syscalls.master,v 1.11 2004/01/20 18:41:51 dillon Exp
*/
#ifndef _SYS_SYSPROTO_H_
off_t msgcid; char msgcid_[PAD_(off_t)];
int flags; char flags_[PAD_(int)];
};
+struct caps_sys_getgen_args {
+#ifdef _KERNEL
+ struct sysmsg sysmsg;
+#endif
+ union usrmsg usrmsg;
+ int portid; char portid_[PAD_(int)];
+};
+struct caps_sys_setgen_args {
+#ifdef _KERNEL
+ struct sysmsg sysmsg;
+#endif
+ union usrmsg usrmsg;
+ int portid; char portid_[PAD_(int)];
+ off_t gen; char gen_[PAD_(off_t)];
+};
struct exec_sys_register_args {
#ifdef _KERNEL
struct sysmsg sysmsg;
int caps_sys_get (struct caps_sys_get_args *);
int caps_sys_wait (struct caps_sys_wait_args *);
int caps_sys_abort (struct caps_sys_abort_args *);
+int caps_sys_getgen (struct caps_sys_getgen_args *);
+int caps_sys_setgen (struct caps_sys_setgen_args *);
int exec_sys_register (struct exec_sys_register_args *);
int exec_sys_unregister (struct exec_sys_unregister_args *);
* Union of syscall args for messaging.
*
* DO NOT EDIT-- this file is automatically generated.
- * $DragonFly: src/sys/sys/sysunion.h,v 1.13 2004/01/20 18:41:51 dillon Exp $
- * created from DragonFly: src/sys/kern/syscalls.master,v 1.10 2004/01/18 12:31:08 dillon Exp
+ * $DragonFly: src/sys/sys/sysunion.h,v 1.14 2004/03/06 22:14:16 dillon Exp $
+ * created from DragonFly: src/sys/kern/syscalls.master,v 1.11 2004/01/20 18:41:51 dillon Exp
*/
union sysunion {
struct caps_sys_get_args caps_sys_get;
struct caps_sys_wait_args caps_sys_wait;
struct caps_sys_abort_args caps_sys_abort;
+ struct caps_sys_getgen_args caps_sys_getgen;
+ struct caps_sys_setgen_args caps_sys_setgen;
struct exec_sys_register_args exec_sys_register;
struct exec_sys_unregister_args exec_sys_unregister;
};