From b5de44291122e0fc2bf68540749f66b3992d3ea2 Mon Sep 17 00:00:00 2001 From: rwatson Date: Mon, 3 Dec 2001 16:12:27 +0000 Subject: o Introduce pr_mtx into struct prison, providing protection for the mutable contents of struct prison (hostname, securelevel, refcount, pr_linux, ...) o Generally introduce mtx_lock()/mtx_unlock() calls throughout kern/ so as to enforce these protections, in particular, in kern_mib.c protection sysctl access to the hostname and securelevel, as well as kern_prot.c access to the securelevel for access control purposes. o Rewrite linux emulator abstractions for accessing per-jail linux mib entries (osname, osrelease, osversion) so that they don't return a pointer to the text in the struct linux_prison, rather, a copy to an array passed into the calls. Likewise, update linprocfs to use these primitives. o Update in_pcb.c to always use prison_getip() rather than directly accessing struct prison. Reviewed by: jhb --- sys/compat/linprocfs/linprocfs.c | 11 +++- sys/compat/linux/linux_mib.c | 132 ++++++++++++++++++++++++++++----------- sys/compat/linux/linux_mib.h | 4 +- sys/compat/linux/linux_misc.c | 7 ++- 4 files changed, 111 insertions(+), 43 deletions(-) (limited to 'sys/compat') diff --git a/sys/compat/linprocfs/linprocfs.c b/sys/compat/linprocfs/linprocfs.c index c64bf11..a23e561 100644 --- a/sys/compat/linprocfs/linprocfs.c +++ b/sys/compat/linprocfs/linprocfs.c @@ -90,6 +90,7 @@ extern int ncpus; #include #endif /* __i386__ */ +#include #include #include #include @@ -444,11 +445,15 @@ linprocfs_douptime(PFS_FILL_ARGS) static int linprocfs_doversion(PFS_FILL_ARGS) { + char osname[LINUX_MAX_UTSNAME]; + char osrelease[LINUX_MAX_UTSNAME]; + + linux_get_osname(td->td_proc, osname); + linux_get_osrelease(td->td_proc, osrelease); + sbuf_printf(sb, "%s version %s (des@freebsd.org) (gcc version " __VERSION__ ")" - " #4 Sun Dec 18 04:30:00 CET 1977\n", - linux_get_osname(td->td_proc), - linux_get_osrelease(td->td_proc)); + " #4 Sun Dec 18 04:30:00 CET 1977\n", osname, osrelease); return (0); } diff --git a/sys/compat/linux/linux_mib.c b/sys/compat/linux/linux_mib.c index 98ea4f0..5ebb35c 100644 --- a/sys/compat/linux/linux_mib.c +++ b/sys/compat/linux/linux_mib.c @@ -35,6 +35,8 @@ #include #include #include +#include +#include #include #include @@ -56,7 +58,7 @@ linux_sysctl_osname(SYSCTL_HANDLER_ARGS) char osname[LINUX_MAX_UTSNAME]; int error; - strcpy(osname, linux_get_osname(req->td->td_proc)); + linux_get_osname(req->td->td_proc, osname); error = sysctl_handle_string(oidp, osname, LINUX_MAX_UTSNAME, req); if (error || req->newptr == NULL) return (error); @@ -77,7 +79,7 @@ linux_sysctl_osrelease(SYSCTL_HANDLER_ARGS) char osrelease[LINUX_MAX_UTSNAME]; int error; - strcpy(osrelease, linux_get_osrelease(req->td->td_proc)); + linux_get_osrelease(req->td->td_proc, osrelease); error = sysctl_handle_string(oidp, osrelease, LINUX_MAX_UTSNAME, req); if (error || req->newptr == NULL) return (error); @@ -111,8 +113,11 @@ SYSCTL_PROC(_compat_linux, OID_AUTO, oss_version, 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 +127,58 @@ get_prison(struct proc *p) 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; } - return (linux_osname); + pr = p->p_ucred->cr_prison; + + mtx_lock(&pr->pr_mtx); + if (pr->pr_linux != NULL) { + lpr = (struct linux_prison *)pr->pr_linux; + if (lpr->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 +188,43 @@ linux_set_osname(p, osname) { 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->pr_mtx); + } else { strcpy(linux_osname, osname); + } return (0); } -char * -linux_get_osrelease(p) +void +linux_get_osrelease(p, dst) struct proc *p; + char *dst; { register struct prison *pr; - register struct linux_prison *lpr; + 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) { + lpr = (struct linux_prison *) pr->pr_linux; + if (lpr->pr_osrelease[0]) { + bcopy(lpr->pr_osrelease, 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 +234,13 @@ linux_set_osrelease(p, osrelease) { 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); } @@ -203,15 +251,27 @@ linux_get_oss_version(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) { + lpr = (struct linux_prison *) pr->pr_linux; + if (lpr->pr_oss_version) { + version = lpr->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 +281,13 @@ linux_set_oss_version(p, oss_version) { 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); } diff --git a/sys/compat/linux/linux_mib.h b/sys/compat/linux/linux_mib.h index 34f5a4e..4bed667 100644 --- a/sys/compat/linux/linux_mib.h +++ b/sys/compat/linux/linux_mib.h @@ -31,10 +31,10 @@ #ifndef _LINUX_MIB_H_ #define _LINUX_MIB_H_ -char* linux_get_osname __P((struct proc *p)); +void linux_get_osname __P((struct proc *p, char *dst)); int linux_set_osname __P((struct proc *p, char *osname)); -char* linux_get_osrelease __P((struct proc *p)); +void linux_get_osrelease __P((struct proc *p, char *dst)); int linux_set_osrelease __P((struct proc *p, char *osrelease)); int linux_get_oss_version __P((struct proc *p)); diff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c index 96fc6dc..605b6ed 100644 --- a/sys/compat/linux/linux_misc.c +++ b/sys/compat/linux/linux_misc.c @@ -688,15 +688,16 @@ int linux_newuname(struct thread *td, struct linux_newuname_args *args) { struct l_new_utsname utsname; - char *osrelease, *osname; + char osname[LINUX_MAX_UTSNAME]; + char osrelease[LINUX_MAX_UTSNAME]; #ifdef DEBUG if (ldebug(newuname)) printf(ARGS(newuname, "*")); #endif - osname = linux_get_osname(td->td_proc); - osrelease = linux_get_osrelease(td->td_proc); + linux_get_osname(td->td_proc, osname); + linux_get_osrelease(td->td_proc, osrelease); bzero(&utsname, sizeof(utsname)); strncpy(utsname.sysname, osname, LINUX_MAX_UTSNAME-1); -- cgit v1.1