[Devel] [PATCH 2/3] Switch UTS namespace to use shadows
Pavel Emelyanov
xemul at openvz.org
Tue Nov 20 03:45:51 PST 2007
The uts sysctl table contains two writable fields
(domainname and nodename), so split the table into
common (read-only) part and writable (shadowed).
This fixes the BUG! You may create a namespace and
then writing to /proc/sys/hostname will cause an
init_uts_ns overwrite.
Signed-off-by: Pavel Emelyanov <xemul at openvz.org>
---
diff --git a/include/linux/utsname.h b/include/linux/utsname.h
index 923db99..7517b36 100644
--- a/include/linux/utsname.h
+++ b/include/linux/utsname.h
@@ -40,6 +40,7 @@ struct new_utsname {
struct uts_namespace {
struct kref kref;
struct new_utsname name;
+ struct ctl_table_header *ctl_header;
};
extern struct uts_namespace init_uts_ns;
@@ -66,6 +67,9 @@ static inline struct new_utsname *init_utsname(void)
return &init_uts_ns.name;
}
+int clone_uts_sysctl(struct uts_namespace *ns);
+void free_uts_sysctl(struct uts_namespace *ns);
+
extern struct rw_semaphore uts_sem;
#endif /* __KERNEL__ */
diff --git a/kernel/utsname.c b/kernel/utsname.c
index 816d7b2..22e40bb 100644
--- a/kernel/utsname.c
+++ b/kernel/utsname.c
@@ -26,13 +26,21 @@ static struct uts_namespace *clone_uts_ns(struct uts_namespace *old_ns)
ns = kmalloc(sizeof(struct uts_namespace), GFP_KERNEL);
if (!ns)
- return ERR_PTR(-ENOMEM);
+ goto err_alloc;
+
+ if (clone_uts_sysctl(ns))
+ goto err_sysctl;
down_read(&uts_sem);
memcpy(&ns->name, &old_ns->name, sizeof(ns->name));
up_read(&uts_sem);
kref_init(&ns->kref);
return ns;
+
+err_sysctl:
+ kfree(ns);
+err_alloc:
+ return ERR_PTR(-ENOMEM);
}
/*
@@ -62,5 +70,6 @@ void free_uts_ns(struct kref *kref)
struct uts_namespace *ns;
ns = container_of(kref, struct uts_namespace, kref);
+ free_uts_sysctl(ns);
kfree(ns);
}
diff --git a/kernel/utsname_sysctl.c b/kernel/utsname_sysctl.c
index c76c064..8a06f0b 100644
--- a/kernel/utsname_sysctl.c
+++ b/kernel/utsname_sysctl.c
@@ -75,6 +75,11 @@ static int sysctl_uts_string(ctl_table *table, int __user *name, int nlen,
#define sysctl_uts_string NULL
#endif
+static struct ctl_table_header *uts_sysctl_shadow(struct ctl_table_header *h)
+{
+ return current->nsproxy->uts_ns->ctl_header;
+}
+
static struct ctl_table uts_kern_table[] = {
{
.ctl_name = KERN_OSTYPE,
@@ -103,6 +108,20 @@ static struct ctl_table uts_kern_table[] = {
.proc_handler = proc_do_uts_string,
.strategy = sysctl_uts_string,
},
+ {}
+};
+
+static struct ctl_table uts_root_table[] = {
+ {
+ .ctl_name = CTL_KERN,
+ .procname = "kernel",
+ .mode = 0555,
+ .child = uts_kern_table,
+ },
+ {}
+};
+
+static struct ctl_table uts_kern_table_sh[] = {
{
.ctl_name = KERN_NODENAME,
.procname = "hostname",
@@ -124,19 +143,44 @@ static struct ctl_table uts_kern_table[] = {
{}
};
-static struct ctl_table uts_root_table[] = {
+static struct ctl_table uts_root_table_sh[] = {
{
.ctl_name = CTL_KERN,
.procname = "kernel",
.mode = 0555,
- .child = uts_kern_table,
+ .child = uts_kern_table_sh,
},
{}
};
+int clone_uts_sysctl(struct uts_namespace *ns)
+{
+ struct ctl_table_header *h;
+ struct ctl_table *tbl;
+
+ h = create_sysctl_shadow(init_uts_ns.ctl_header);
+ if (h == NULL)
+ return -ENOMEM;
+
+ tbl = h->ctl_table->child;
+
+ tbl[0].data = ns->name.nodename;
+ tbl[1].data = ns->name.domainname;
+
+ ns->ctl_header = h;
+ return 0;
+}
+
+void free_uts_sysctl(struct uts_namespace *ns)
+{
+ free_sysctl_shadow(ns->ctl_header);
+}
+
static int __init utsname_sysctl_init(void)
{
register_sysctl_table(uts_root_table);
+ init_uts_ns.ctl_header = register_sysctl_table_shadow(uts_root_table_sh,
+ uts_sysctl_shadow);
return 0;
}
_______________________________________________
Containers mailing list
Containers at lists.linux-foundation.org
https://lists.linux-foundation.org/mailman/listinfo/containers
More information about the Devel
mailing list