Index: compat/linux/linux_mib.c =================================================================== RCS file: /home/ncvs/src/sys/compat/linux/linux_mib.c,v retrieving revision 1.12 diff -u -r1.12 linux_mib.c --- compat/linux/linux_mib.c 2001/06/15 08:18:24 1.12 +++ compat/linux/linux_mib.c 2001/09/02 16:16:48 @@ -56,7 +56,7 @@ char osname[LINUX_MAX_UTSNAME]; int error; - strcpy(osname, linux_get_osname(req->p)); + linux_get_osname(req->p, osname); error = sysctl_handle_string(oidp, osname, LINUX_MAX_UTSNAME, req); if (error || req->newptr == NULL) return (error); @@ -77,7 +77,7 @@ char osrelease[LINUX_MAX_UTSNAME]; int error; - strcpy(osrelease, linux_get_osrelease(req->p)); + linux_get_osrelease(req->p, osrelease); error = sysctl_handle_string(oidp, osrelease, LINUX_MAX_UTSNAME, req); if (error || req->newptr == NULL) return (error); @@ -111,8 +111,11 @@ 0, 0, linux_sysctl_oss_version, "I", "Linux OSS version"); +/* + * Returns holding the prison mutex if return non-NULL. + */ static struct linux_prison * -get_prison(struct proc *p) +linux_get_prison(struct proc *p) { register struct prison *pr; register struct linux_prison *lpr; @@ -122,30 +125,57 @@ pr = p->p_ucred->cr_prison; + /* + * Rather than hold the prison mutex during allocation, check to + * see if we need to allocate while holding the mutex, release it, + * allocate, then once we've allocated the memory, check again to + * see if it's still needed, and set if appropriate. If it's not, + * we release the mutex again to FREE(), and grab it again so as + * to release holding the lock. + */ + mtx_lock(pr->pr_mtx); if (pr->pr_linux == NULL) { + mtx_unlock(pr->pr_mtx); MALLOC(lpr, struct linux_prison *, sizeof *lpr, M_PRISON, M_WAITOK|M_ZERO); - pr->pr_linux = lpr; + mtx_lock(pr->pr_mtx); + if (pr->pr_linux == NULL) { + pr->pr_linux = lpr; + } else { + mtx_unlock(pr->pr_mtx); + FREE(lpr, M_PRISON); + mtx_lock(pr->pr_mtx); + } } return (pr->pr_linux); } -char * -linux_get_osname(p) +void +linux_get_osname(p, dst) struct proc *p; + char *dst; { register struct prison *pr; register struct linux_prison *lpr; - pr = p->p_ucred->cr_prison; - if (pr != NULL && pr->pr_linux != NULL) { - lpr = pr->pr_linux; - if (lpr->pr_osname[0]) - return (lpr->pr_osname); + if (p->p_ucred->cr_prison == NULL) { + bcopy(linux_osname, dst, LINUX_MAX_UTSNAME); + return; } + + pr = p->p_ucred->cr_prison; - return (linux_osname); + mtx_lock(pr->pr_mtx); + if (pr->pr_linux != NULL) { + if (pr->pr_linux->pr_osname[0]) { + bcopy(lpr->pr_osname, dst, LINUX_MAX_UTSNAME); + mtx_unlock(pr->pr_mtx); + return; + } + } + mtx_unlock(pr->pr_mtx); + bcopy(linux_osname, dst, LINUX_MAX_UTSNAME); } int @@ -155,30 +185,41 @@ { register struct linux_prison *lpr; - lpr = get_prison(p); - if (lpr != NULL) + lpr = linux_get_prison(p); + if (lpr != NULL) { strcpy(lpr->pr_osname, osname); - else + mtx_unlock(p->p_ucred->cr_prison->p_mtx); + } else { strcpy(linux_osname, osname); + } return (0); } -char * -linux_get_osrelease(p) +void +linux_get_osrelease(p, dst) struct proc *p; + chat *dst; { register struct prison *pr; - register struct linux_prison *lpr; - pr = p->p_ucred->cr_prison; - if (pr != NULL && pr->pr_linux != NULL) { - lpr = pr->pr_linux; - if (lpr->pr_osrelease[0]) - return (lpr->pr_osrelease); + if (p->p_ucred->cr_prison == NULL) { + bcopy(linux_osrelease, dst, LINUX_MAX_UTSNAME); + return; } - return (linux_osrelease); + pr = p->p_ucred->cr_prison; + + mtx_lock(pr->pr_mtx); + if (pr->pr_linux != NULL) { + if (pr->pr_linux->pr_osrelease[0]) { + bcopy(pr->pr_linux->pr_osname, dst, LINUX_MAX_UTSNAME); + mtx_unlock(pr->pr_mtx); + return; + } + } + mtx_unlock(pr->pr_mtx); + bcopy(linux_osrelease, dst, LINUX_MAX_UTSNAME); } int @@ -188,11 +229,13 @@ { register struct linux_prison *lpr; - lpr = get_prison(p); - if (lpr != NULL) + lpr = linux_get_prison(p); + if (lpr != NULL) { strcpy(lpr->pr_osrelease, osrelease); - else + mtx_unlock(p->p_ucred->cr_prison->pr_mtx); + } else { strcpy(linux_osrelease, osrelease); + } return (0); } @@ -202,16 +245,26 @@ struct proc *p; { register struct prison *pr; - register struct linux_prison *lpr; + int version; + if (p->p_ucred->cr_prison == NULL) + return (linux_oss_version); + pr = p->p_ucred->cr_prison; - if (pr != NULL && pr->pr_linux != NULL) { - lpr = pr->pr_linux; - if (lpr->pr_oss_version) - return (lpr->pr_oss_version); + + mtx_lock(pr->pr_mtx); + if (pr->pr_linux != NULL) { + if (pr->pr_linux->pr_oss_version) { + version = pr->pr_linux->pr_oss_version; + } else { + version = linux_oss_version; + } + } else { + version = linux_oss_version; } + mtx_unlock(pr->pr_mtx); - return (linux_oss_version); + return (version); } int @@ -221,11 +274,13 @@ { register struct linux_prison *lpr; - lpr = get_prison(p); - if (lpr != NULL) + lpr = linux_get_prison(p); + if (lpr != NULL) { lpr->pr_oss_version = oss_version; - else + mtx_unlock(p->p_ucred->cr_prison->pr_mtx); + } else { linux_oss_version = oss_version; + } return (0); } Index: fs/procfs/procfs_status.c =================================================================== RCS file: /home/ncvs/src/sys/fs/procfs/procfs_status.c,v retrieving revision 1.32 diff -u -r1.32 procfs_status.c --- fs/procfs/procfs_status.c 2001/07/05 17:10:43 1.32 +++ fs/procfs/procfs_status.c 2001/09/03 03:04:06 @@ -43,10 +43,10 @@ #include #include #include +#include #include #include #include -#include #include #include #include @@ -166,11 +166,14 @@ DOCHECK(); } - if (jailed(p->p_ucred)) + if (jailed(p->p_ucred)) { + mtx_lock(&p->p_ucred->cr_prison->pr_mtx); ps += snprintf(ps, psbuf + sizeof(psbuf) - ps, " %s", p->p_ucred->cr_prison->pr_host); - else + mtx_unlock(&p->p_ucred->cr_prison->pr_mtx); + } else { ps += snprintf(ps, psbuf + sizeof(psbuf) - ps, " -"); + } DOCHECK(); ps += snprintf(ps, psbuf + sizeof(psbuf) - ps, "\n"); DOCHECK(); Index: kern/kern_jail.c =================================================================== RCS file: /home/ncvs/src/sys/kern/kern_jail.c,v retrieving revision 1.12 diff -u -r1.12 kern_jail.c --- kern/kern_jail.c 2001/09/01 03:04:31 1.12 +++ kern/kern_jail.c 2001/09/03 03:01:57 @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -82,10 +83,13 @@ error = chroot(p, &ca); if (error) goto bail; + pr->pr_ref = 1; + + mtx_init(&pr->pr_mtx, "jail lock", MTX_DEF); + /* XXX not proc locking safe */ p->p_ucred = crcopy(p->p_ucred); p->p_ucred->cr_prison = pr; - pr->pr_ref = 1; mtx_unlock(&Giant); return (0); @@ -100,19 +104,34 @@ prison_free(struct prison *pr) { + mtx_lock(&pr->pr_mtx); pr->pr_ref--; if (pr->pr_ref == 0) { + mtx_unlock(&pr->pr_mtx); + mtx_destroy(&pr->pr_mtx); if (pr->pr_linux != NULL) FREE(pr->pr_linux, M_PRISON); FREE(pr, M_PRISON); + return; } + mtx_unlock(&pr->pr_mtx); + return; } void prison_hold(struct prison *pr) { + mtx_lock(&pr->pr_mtx); pr->pr_ref++; + mtx_unlock(&pr->pr_mtx); +} + +u_int32_t +prison_getip(struct ucred *cred) +{ + + return (cred->cr_prison->pr_ip); } int Index: kern/kern_mib.c =================================================================== RCS file: /home/ncvs/src/sys/kern/kern_mib.c,v retrieving revision 1.43 diff -u -r1.43 kern_mib.c --- kern/kern_mib.c 2001/07/27 15:52:49 1.43 +++ kern/kern_mib.c 2001/09/03 03:05:31 @@ -45,6 +45,8 @@ #include #include #include +#include +#include #include #include @@ -150,11 +152,34 @@ int error; if (jailed(req->p->p_ucred)) { + char tmphostname[MAXHOSTNAMELEN]; + if (!jail_set_hostname_allowed && req->newptr) - return(EPERM); - error = sysctl_handle_string(oidp, - req->p->p_ucred->cr_prison->pr_host, + return (EPERM); + + /* + * Process is in jail, so make a local copy of jail + * hostname to get/set so we don't have to hold the jail + * mutex during the sysctl copyin/copyout activities. + */ + mtx_lock(&req->p->p_ucred->cr_prison->pr_mtx); + bcopy(req->p->p_ucred->cr_prison->pr_host, tmphostname, + MAXHOSTNAMELEN); + mtx_unlock(&req->p->p_ucred->cr_prison->pr_mtx); + + error = sysctl_handle_string(oidp, tmphostname, sizeof req->p->p_ucred->cr_prison->pr_host, req); + + if (req->newptr && error == 0) { + /* + * Copy the locally set hostname to the jail, if + * appropriate. + */ + mtx_lock(&req->p->p_ucred->cr_prison->pr_mtx); + bcopy(tmphostname, req->p->p_ucred->cr_prison->pr_host, + MAXHOSTNAMELEN); + mtx_unlock(&req->p->p_ucred->cr_prison->pr_mtx); + } } else error = sysctl_handle_string(oidp, hostname, sizeof hostname, req); Index: netinet/in_pcb.c =================================================================== RCS file: /home/ncvs/src/sys/netinet/in_pcb.c,v retrieving revision 1.87 diff -u -r1.87 in_pcb.c --- netinet/in_pcb.c 2001/08/04 17:10:13 1.87 +++ netinet/in_pcb.c 2001/09/02 15:23:58 @@ -508,7 +508,7 @@ cred = inp->inp_socket->so_cred; if (inp->inp_laddr.s_addr == INADDR_ANY && jailed(cred)) { bzero(&sa, sizeof (sa)); - sa.sin_addr.s_addr = htonl(cred->cr_prison->pr_ip); + sa.sin_addr.s_addr = htonl(prison_getip(cred->cr_prison)); sa.sin_len=sizeof (sa); sa.sin_family = AF_INET; error = in_pcbbind(inp, (struct sockaddr *)&sa, p); @@ -1054,7 +1054,7 @@ { if (!jailed(p->p_ucred)) return (0); - if (ntohl(inp->inp_laddr.s_addr) == p->p_ucred->cr_prison->pr_ip) + if (ntohl(inp->inp_laddr.s_addr) == prison_getip(p->p_ucred)) return (0); return (1); } Index: sys/jail.h =================================================================== RCS file: /home/ncvs/src/sys/sys/jail.h,v retrieving revision 1.11 diff -u -r1.11 jail.h --- sys/jail.h 2001/02/21 06:39:57 1.11 +++ sys/jail.h 2001/09/03 03:02:17 @@ -35,19 +35,25 @@ * ucreds's of the inmates. pr_ref keeps track of them and is used to * delete the struture when the last inmate is dead. * - * XXX: Note: this structure needs a mutex to protect the reference count - * and other mutable fields (pr_host, pr_linux). + * Lock key: + * (p) locked by pr_mutex + * (c) set only during creation before the structure is shared, no mutex + * required to read */ - +struct mtx; struct prison { - int pr_ref; - char pr_host[MAXHOSTNAMELEN]; - u_int32_t pr_ip; - void *pr_linux; + int pr_ref; /* (p) refcount */ + char pr_host[MAXHOSTNAMELEN]; /* (p) jail hostname */ + u_int32_t pr_ip; /* (c) ip addr host + * byte order */ + void *pr_linux; /* (p) linux abi */ + struct mtx pr_mtx; }; /* * Sysctl-set variables that determine global jail policy + * + * XXX MIB entries will need to be protected by a mutex. */ extern int jail_set_hostname_allowed; extern int jail_socket_unixiproute_only; @@ -61,6 +67,7 @@ int jailed __P((struct ucred *cred)); int prison_check __P((struct ucred *cred1, struct ucred *cred2)); void prison_free __P((struct prison *pr)); +u_int32_t prison_getip __P((struct ucred *cred)); void prison_hold __P((struct prison *pr)); int prison_if __P((struct ucred *cred, struct sockaddr *sa)); int prison_ip __P((struct ucred *cred, int flag, u_int32_t *ip));