Date: Sun, 5 Nov 2006 15:01:00 GMT From: Alex Lyashkov <als@FreeBSD.org> To: Perforce Change Reviews <perforce@FreeBSD.org> Subject: PERFORCE change 109286 for review Message-ID: <200611051501.kA5F10Vn090660@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=109286 Change 109286 by als@als_head on 2006/11/05 15:00:14 add prof of concept code to allow modules corectly init from jails. each jail must call kldload "name", and kernel fake this. Affected files ... .. //depot/projects/jail2/sys/kern/kern_jail2_init.c#2 edit .. //depot/projects/jail2/sys/kern/kern_linker.c#6 edit .. //depot/projects/jail2/sys/kern/uipc_sem.c#4 edit .. //depot/projects/jail2/sys/sys/jail.h#6 edit .. //depot/projects/jail2/sys/sys/jail2_init.h#3 edit .. //depot/projects/jail2/sys/sys/linker.h#3 edit Differences ... ==== //depot/projects/jail2/sys/kern/kern_jail2_init.c#2 (text+ko) ==== @@ -3,59 +3,76 @@ #include <sys/param.h> #include <sys/kernel.h> -#include <sys/lock.h> -#include <sys/rwlock.h> +#include <sys/sx.h> #include <sys/queue.h> #include <sys/jail.h> #include <sys/jail2_init.h> -static struct jail_sysinitlist j_sysinit; -static struct rwlock j_sysinit_lock; -RW_SYSINIT(jsysinit, &j_sysinit_lock, "Jail2 sys[un]init lock"); +static struct jail_initlist j_sysinit; + +static struct sx j_sysinit_lock; +SX_SYSINIT(jsysinit, &j_sysinit_lock, "Jail2 sys[un]init lock"); + +#define jprint(a...) printf(a) -void jailsysinit_add(struct jail_sysinit *sinit) +void jailsysinit_add(struct jailinit *sinit) { - struct jail_sysinit *cur; + struct jailinit *cur; - rw_wlock(&j_sysinit_lock); - TAILQ_FOREACH(cur, &j_sysinit, list) { - if (cur->subsystem < sinit->subsystem || - (cur->subsystem == sinit->subsystem && - cur->order <= sinit->order)) { - TAILQ_INSERT_AFTER(&j_sysinit, cur, sinit, list); - break; + jprint("jail add init %p - %d/%d\n", sinit, + sinit->subsystem, sinit->order); + sx_xlock(&j_sysinit_lock); + if (TAILQ_EMPTY(&j_sysinit)) { + TAILQ_INSERT_HEAD(&j_sysinit, sinit, list); + } else { + TAILQ_FOREACH(cur, &j_sysinit, list) { + if (cur->subsystem < sinit->subsystem || + (cur->subsystem == sinit->subsystem && + cur->order <= sinit->order)) { + TAILQ_INSERT_AFTER(&j_sysinit, cur, sinit, list); + break; + } } } - rw_wunlock(&j_sysinit_lock); + sx_xunlock(&j_sysinit_lock); } -void jailsysinit_del(struct jail_sysinit *sinit) +void jailsysinit_del(struct jailinit *sinit) { - rw_wlock(&j_sysinit_lock); + jprint("jail del init %p - %d/%d\n", sinit, + sinit->subsystem, sinit->order); + + sx_xlock(&j_sysinit_lock); TAILQ_REMOVE(&j_sysinit, sinit, list); - rw_wunlock(&j_sysinit_lock); + sx_xunlock(&j_sysinit_lock); } void prison_init(struct prison *pr) { - struct jail_sysinit *cur; + struct jailinit *cur; - rw_rlock(&j_sysinit_lock); + jprint("start jail init\n"); + sx_slock(&j_sysinit_lock); TAILQ_FOREACH(cur, &j_sysinit, list) { + jprint("jail init %p - %d/%d\n", cur, + cur->subsystem, cur->order); cur->init(pr); } - rw_runlock(&j_sysinit_lock); + sx_sunlock(&j_sysinit_lock); } void prinson_fini(struct prison *pr) { - struct jail_sysinit *cur; + struct jailinit *cur; - rw_rlock(&j_sysinit_lock); - TAILQ_FOREACH_REVERSE(cur, &j_sysinit, jail_sysinitlist, list) { + jprint("start jail fini\n"); + sx_slock(&j_sysinit_lock); + TAILQ_FOREACH_REVERSE(cur, &j_sysinit, jail_initlist, list) { + jprint("jail fini %p - %d/%d\n", cur, + cur->subsystem, cur->order); cur->fini(pr); } - rw_runlock(&j_sysinit_lock); + sx_sunlock(&j_sysinit_lock); } ==== //depot/projects/jail2/sys/kern/kern_linker.c#6 (text+ko) ==== @@ -31,6 +31,8 @@ #include "opt_hwpmc_hooks.h" #include "opt_mac.h" +#define KLD_DEBUG + #include <sys/param.h> #include <sys/kernel.h> #include <sys/systm.h> @@ -55,14 +57,17 @@ #include "linker_if.h" +#ifdef JAIL #include <sys/jail.h> +#include <sys/jail2_init.h> +#endif #ifdef HWPMC_HOOKS #include <sys/pmckern.h> #endif #ifdef KLD_DEBUG -int kld_debug = 0; +int kld_debug = 1; #endif #define KLD_LOCK() sx_xlock(&kld_sx) @@ -138,6 +143,13 @@ struct mod_depend *verinfo, struct linker_file **lfpp); static modlist_t modlist_lookup2(const char *name, struct mod_depend *verinfo); +#ifdef JAIL +static int jail_load_module(struct thread *td, const char *kldname, const char *modname); +static int jail_unload_module(struct thread *td, linker_file_t lf); +static int jail_kldnext(struct thread *td, struct kldnext_args *uap); +#endif + + static char * linker_strdup(const char *str) { @@ -310,6 +322,127 @@ mtx_unlock(&Giant); } +#ifdef JAIL + +static void +linker_file_register_jailinit(linker_file_t lf, struct prison *pr) +{ + struct jailinit **start, **stop, **sipp, **xipp, *save; + + KLD_DPF(FILE, + ("linker_file_register_jailinit: registering jailinit for %s\n", + lf->filename)); + + if (linker_file_lookup_set(lf, "jailinit_set", &start, &stop, NULL) != 0) + return; + + lf->flags |= LINKER_ALLOW_JAIL; + /* perform sorting - get from liker_file_sysuninit */ + for (sipp = start; sipp < stop; sipp++) { + for (xipp = sipp + 1; xipp < stop; xipp++) { + if ((*sipp)->subsystem < (*xipp)->subsystem || + ((*sipp)->subsystem == (*xipp)->subsystem && + (*sipp)->order >= (*xipp)->order)) + continue; /* skip */ + save = *sipp; + *sipp = *xipp; + *xipp = save; + } + } + + mtx_lock(&Giant); + for (sipp = start; sipp < stop; sipp++) { + if ((*sipp)->subsystem == SI_SUB_DUMMY) + continue; /* skip dummy task(s) */ + + if (!pr_jailed(pr)) + jailsysinit_add(*sipp); + /* Call function */ + (*((*sipp)->init)) (pr); + } + mtx_unlock(&Giant); + +} + +static void +linker_file_jailuninit(linker_file_t lf, struct prison *pr) +{ + struct jailinit **start, **stop, **sipp, **xipp, *save; + + KLD_DPF(FILE, + ("linker_file_jailuninit: unregistering jailinit for %s\n", + lf->filename)); + + if (linker_file_lookup_set(lf, "jailinit_set", &start, &stop, NULL) != 0) + return; + + /* perform sorting - get from liker_file_sysuninit */ + for (sipp = start; sipp < stop; sipp++) { + for (xipp = sipp + 1; xipp < stop; xipp++) { + if ((*sipp)->subsystem > (*xipp)->subsystem || + ((*sipp)->subsystem == (*xipp)->subsystem && + (*sipp)->order >= (*xipp)->order)) + continue; /* skip */ + save = *sipp; + *sipp = *xipp; + *xipp = save; + } + } + + mtx_lock(&Giant); + for (sipp = start; sipp < stop; sipp++) { + if ((*sipp)->subsystem == SI_SUB_DUMMY) + continue; /* skip dummy task(s) */ + + if (!pr_jailed(pr)) + jailsysinit_del(*sipp); + /* Call function */ + (*((*sipp)->fini)) (pr); + } + mtx_unlock(&Giant); +} + +static int +linker_file_canshow(linker_file_t lf, struct prison *pr) +{ + struct jailinit **start, **stop, **sipp, **xipp, *save; + int show = 1; + + KLD_DPF(FILE, + ("linker_file_can show: for %s\n", lf->filename)); + + if (linker_file_lookup_set(lf, "jailinit_set", &start, &stop, NULL) != 0) + return (0); + + /* perform sorting - get from liker_file_sysuninit */ + for (sipp = start; sipp < stop; sipp++) { + for (xipp = sipp + 1; xipp < stop; xipp++) { + if ((*sipp)->subsystem > (*xipp)->subsystem || + ((*sipp)->subsystem == (*xipp)->subsystem && + (*sipp)->order >= (*xipp)->order)) + continue; /* skip */ + save = *sipp; + *sipp = *xipp; + *xipp = save; + } + } + + mtx_lock(&Giant); + for (sipp = start; sipp < stop; sipp++) { + if ((*sipp)->subsystem == SI_SUB_DUMMY) + continue; /* skip dummy task(s) */ + /* Call function */ + show &= (*((*sipp)->is_show))(pr); + if (show == 0) + break; + } + mtx_unlock(&Giant); + + return (show); +} + +#endif + static int linker_file_register_modules(linker_file_t lf) { @@ -356,6 +489,9 @@ { linker_file_register_modules(linker_kernel_file); +#ifdef JAIL + linker_file_register_jailinit(linker_kernel_file, &jail_0); +#endif } SYSINIT(linker_kernel, SI_SUB_KLD, SI_ORDER_ANY, linker_init_kernel_modules, 0) @@ -406,6 +542,9 @@ } linker_file_register_sysctls(lf); linker_file_sysinit(lf); +#ifdef JAIL + linker_file_register_jailinit(lf, &jail_0); +#endif lf->flags |= LINKER_FILE_LINKED; *result = lf; return (0); @@ -612,6 +751,7 @@ * link error. */ if (file->flags & LINKER_FILE_LINKED) { + linker_file_jailuninit(file, &jail_0); linker_file_sysuninit(file); linker_file_unregister_sysctls(file); } @@ -837,6 +977,7 @@ } #endif + /* * Syscalls. */ @@ -849,14 +990,15 @@ #ifdef HWPMC_HOOKS struct pmckern_map_in pkm; #endif + struct ucred *tdcred = td->td_ucred; const char *kldname, *modname; linker_file_t lf; int error; - if ((error = securelevel_gt(td->td_ucred, 0)) != 0) + if ((error = securelevel_gt(tdcred, 0)) != 0) return (error); - if ((error = suser(td)) != 0) + if ((error = suser_cred(tdcred, SUSER_ALLOWJAIL)) != 0) return (error); /* @@ -871,8 +1013,15 @@ kldname = NULL; modname = file; } + KLD_LOCK(); +#ifdef JAIL + if (jailed(tdcred)) { + error = jail_load_module(td, kldname, modname); + goto unlock; + } +#endif + - KLD_LOCK(); error = linker_load_module(kldname, modname, NULL, NULL, &lf); if (error) goto unlock; @@ -917,17 +1066,25 @@ #ifdef HWPMC_HOOKS struct pmckern_map_out pkm; #endif + struct ucred *tdcred = td->td_ucred; linker_file_t lf; int error = 0; - if ((error = securelevel_gt(td->td_ucred, 0)) != 0) + if ((error = securelevel_gt(tdcred, 0)) != 0) return (error); - if ((error = suser(td)) != 0) + if ((error = suser_cred(tdcred, SUSER_ALLOWJAIL)) != 0) return (error); KLD_LOCK(); lf = linker_find_file_by_id(fileid); +#ifdef JAIL + if (jailed(tdcred)) { + error = jail_unload_module(td, lf); + goto unlock; + } +#endif + if (lf) { KLD_DPF(FILE, ("kldunload: lf->userrefs=%d\n", lf->userrefs)); if (lf->userrefs == 0) { @@ -955,6 +1112,9 @@ if (error == 0) PMC_CALL_HOOK(td, PMC_FN_KLD_UNLOAD, (void *) &pkm); #endif +#ifdef JAIL +unlock: +#endif KLD_UNLOCK(); return (error); } @@ -1032,6 +1192,10 @@ if (error) return (error); #endif +#ifdef JAIL + if (pr_jailed(td_prison(td))) + return jail_kldnext(td, uap); +#endif KLD_LOCK(); if (uap->fileid == 0) { @@ -1466,6 +1630,7 @@ &si_stop, NULL) == 0) sysinit_add(si_start, si_stop); linker_file_register_sysctls(lf); + linker_file_register_jailinit(lf, &jail_0); lf->flags |= LINKER_FILE_LINKED; } /* woohoo! we made it! */ @@ -1820,6 +1985,101 @@ } #endif +#ifdef JAIL +static int +jail_load_module(struct thread *td, const char *kldname, const char *modname) +{ + struct prison *pr = td_prison(td); + linker_file_t lf; + const char *filename; + char *pathname; + + KLD_LOCK_ASSERT(); + + if (modname == NULL) { + /* + * We have to load KLD + */ + pathname = linker_search_kld(kldname); + } else { +#if 0 + /* XXX ? */ + if (modlist_lookup2(modname, verinfo) != NULL) + return (EEXIST); +#endif + if (kldname != NULL) + pathname = linker_strdup(kldname); + else if (rootvnode == NULL) + pathname = NULL; + else + /* + * Need to find a KLD with required module + */ + pathname = linker_search_module(modname, + strlen(modname), NULL); + } + if (pathname == NULL) + return (ENOENT); + + + /* + * Can't load more than one file with the same basename XXX: + * Actually it should be possible to have multiple KLDs with + * the same basename but different path because they can + * provide different versions of the same modules. + */ + filename = linker_basename(pathname); + lf = linker_find_file_by_name(filename); + if (lf == NULL) + return (ESRCH); + + if ((lf->flags & LINKER_ALLOW_JAIL) == 0) + return (EPERM); + + lf->refs++; + linker_file_register_jailinit(lf, pr); + + return (0); +} + +static int +jail_unload_module(struct thread *td, linker_file_t lf) +{ + struct prison *pr = td_prison(td); + + if ((lf->flags & LINKER_ALLOW_JAIL) == 0) + return (EPERM); + + linker_file_jailuninit(lf, pr); + lf->refs--; + + return (0); +} + +int jail_kldnext(struct thread *td, struct kldnext_args *uap) +{ + linker_file_t lftmp; + struct prison *pr = td_prison(td); + int tmp = uap->fileid; + + KLD_LOCK(); + TAILQ_FOREACH(lftmp, &linker_files, link) { + if ((lftmp->id > tmp) && (linker_file_canshow(lftmp, pr))) { + td->td_retval[0] = lftmp->id; + tmp = 0; + goto exit; + } + } + td->td_retval[0] = 0; + tmp = ENOENT; +exit: + KLD_UNLOCK(); + + return (tmp); +} + +#endif + /* * Find a file which contains given module and load it, if "parent" is not * NULL, register a reference to it. ==== //depot/projects/jail2/sys/kern/uipc_sem.c#4 (text+ko) ==== @@ -64,6 +64,11 @@ #include <security/mac/mac_framework.h> +#ifdef JAIL +#include <sys/jail.h> +#include <sys/jail2_init.h> +#endif + static int sem_count_proc(struct proc *p); static struct ksem *sem_lookup_byname(const char *name); static int sem_create(struct thread *td, const char *name, @@ -285,7 +290,7 @@ int oflag; mode_t mode; unsigned int value; - semid_t *idp; + semid_t *idp; }; int ksem_open(struct thread *td, struct ksem_open_args *uap); #endif @@ -374,7 +379,7 @@ } } else { DP(("sem_create: about to add to list...\n")); - LIST_INSERT_HEAD(&ksem_head, ksnew, ks_entry); + LIST_INSERT_HEAD(&ksem_head, ksnew, ks_entry); DP(("sem_create: setting list bit...\n")); ksnew->ks_onlist = 1; DP(("sem_create: done, about to unlock...\n")); @@ -424,7 +429,7 @@ ks->ks_uid, ks->ks_gid, ks->ks_mode)); if (uc->cr_prison->pr_id != ks->pr_id) return (EPERM); - + if ((uc->cr_uid == ks->ks_uid && (ks->ks_mode & S_IWUSR) != 0) || (uc->cr_gid == ks->ks_gid && (ks->ks_mode & S_IWGRP) != 0) || (ks->ks_mode & S_IWOTH) != 0 || suser(td) == 0) @@ -461,7 +466,7 @@ static int sem_hasopen(struct thread *td, struct ksem *ks) { - + return ((ks->ks_name == NULL && sem_perm(td, ks) == 0) || sem_getuser(td->td_proc, ks) != NULL); } @@ -512,7 +517,7 @@ }; int ksem_unlink(struct thread *td, struct ksem_unlink_args *uap); #endif - + int ksem_unlink(struct thread *td, struct ksem_unlink_args *uap) { @@ -547,7 +552,7 @@ DP(("sem_unlink: '%s' ks = %p, error = %d\n", name, ks, error)); if (error == 0) { LIST_REMOVE(ks, ks_entry); - LIST_INSERT_HEAD(&ksem_deadhead, ks, ks_entry); + LIST_INSERT_HEAD(&ksem_deadhead, ks, ks_entry); sem_rel(ks); } mtx_unlock(&sem_lock); @@ -925,7 +930,7 @@ static void sem_exechook(void *arg, struct proc *p, struct image_params *imgp __unused) { - sem_exithook(arg, p); + sem_exithook(arg, p); } static void @@ -1003,3 +1008,36 @@ DECLARE_MODULE(sem, sem_mod, SI_SUB_SYSV_SEM, SI_ORDER_FIRST); MODULE_VERSION(sem, 1); + +#ifdef JAIL +static void +ksem_jinit(void *data) +{ + struct prison *pr = data; + + printf("ksem jailinit\n"); + + pr->mod_data[JMODULE_KSEM] = (void *)0xdeadc0de; +} + +static void +ksem_juninit(void *data) +{ + struct prison *pr = data; + + printf("ksem jailuninit\n"); + + pr->mod_data[JMODULE_KSEM] = NULL; +} + +static int +ksem_jshow(struct prison *pr) +{ + printf("ksem checkshow %p\n", pr->mod_data[JMODULE_KSEM]); + + return (pr->mod_data[JMODULE_KSEM] != NULL); +} + +JAILINIT(ksem, SI_SUB_SYSV_SEM, SI_ORDER_FIRST, &ksem_jinit, &ksem_juninit, &ksem_jshow); + +#endif ==== //depot/projects/jail2/sys/sys/jail.h#6 (text+ko) ==== @@ -29,7 +29,7 @@ }; #define XPRISON_VERSION 1 -#define JMODULE_COUNT 3 +#define JMODULE_COUNT 4 #ifndef _KERNEL @@ -146,6 +146,8 @@ void prison_remote_ip(struct ucred *cred, uint32_t *ip); /* INLINES */ +#define td_prison(td) ((td)->td_ucred->cr_prison) + /* * Return 1 if the passed credential is in a jail, otherwise 0. */ ==== //depot/projects/jail2/sys/sys/jail2_init.h#3 (text+ko) ==== @@ -6,26 +6,49 @@ JMODULE_NODATA = -1, JMODULE_SYSVMSQ = 0, JMODULE_SYSVSEM = 1, - JMODULE_SYSVSHM = 2 + JMODULE_SYSVSHM = 2, + JMODULE_KSEM = 3 }; #ifdef _KERNEL #include <sys/queue.h> -struct jail_sysinit { - TAILQ_ENTRY(jail_sysinit) list; /* */ - uint32_t id; +struct prison; +typedef int (*jailinit_sfunc_t)(struct prison *pr); + +struct jailinit { + TAILQ_ENTRY(jailinit) list; /* */ + uint32_t id; /* XXX ? */ enum sysinit_sub_id subsystem; /* subsystem identifier*/ enum sysinit_elem_order order; /* init order within subsystem*/ sysinit_nfunc_t init; /* init per jail data */ sysinit_nfunc_t fini; /* detroy per jail */ + jailinit_sfunc_t is_show; /* is module show for prison ?*/ }; -TAILQ_HEAD(jail_sysinitlist, jail_sysinit); +TAILQ_HEAD(jail_initlist, jailinit); + +/* + * Copy from SYSINIT/SYSUNINIT + */ +#define C_JAILINIT(uniquifier, subsys, suborder, initfunc, finifunc, showfunc) \ + static struct jailinit uniquifier ## _jailinit = { \ + subsystem : (subsys), \ + order : (suborder), \ + init : (initfunc), \ + fini : (finifunc), \ + is_show : (showfunc), \ + }; \ + DATA_SET(jailinit_set,uniquifier ## _jailinit); + +#define JAILINIT(uniquifier, subsystem, order, func_init, func_fini, func_show) \ + C_JAILINIT(uniquifier, subsystem, order, \ + (sysinit_nfunc_t)func_init, (sysinit_nfunc_t)func_fini, (jailinit_sfunc_t)func_show) + -extern void jailsysinit_add(struct jail_sysinit *sinit); -extern void jailsysinit_del(struct jail_sysinit *sinit); +extern void jailsysinit_add(struct jailinit *sinit); +extern void jailsysinit_del(struct jailinit *sinit); extern void prison_init(struct prison *pr); extern void prinson_fini(struct prison *pr); ==== //depot/projects/jail2/sys/sys/linker.h#3 (text+ko) ==== @@ -71,6 +71,8 @@ int userrefs; /* kldload(2) count */ int flags; #define LINKER_FILE_LINKED 0x1 /* file has been fully linked */ +#define LINKER_ALLOW_JAIL 0x2 /* file has been allow to "load" in jail */ + TAILQ_ENTRY(linker_file) link; /* list of all loaded files */ char* filename; /* file which was loaded */ int id; /* unique id */
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200611051501.kA5F10Vn090660>