PERFORCE change 109286 for review
Alex Lyashkov
als at FreeBSD.org
Sun Nov 5 15:01:02 UTC 2006
http://perforce.freebsd.org/chv.cgi?CH=109286
Change 109286 by als at 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 */
More information about the p4-projects
mailing list