Skip to content

Commit

Permalink
[PATCH] sysctl: simplify sysctl_uts_string
Browse files Browse the repository at this point in the history
The binary interface to the namespace sysctls was never implemented resulting
in some really weird things if you attempted to use sys_sysctl to read your
hostname for example.

This patch series simples the code a little and implements the binary sysctl
interface.

In testing this patch series I discovered that our 32bit compatibility for the
binary sysctl interface is imperfect.  In particular KERN_SHMMAX and
KERN_SMMALL are size_t sized quantities and are returned as 8 bytes on to
32bit binaries using a x86_64 kernel.  However this has existing for a long
time so it is not a new regression with the namespace work.

Gads the whole sysctl thing needs work before it stops being easy to shoot
yourself in the foot.

Looking forward a little bit we need a better way to handle sysctls and
namespaces as our current technique will not work for the network namespace.
I think something based on the current overlapping sysctl trees will work but
the proc side needs to be redone before we can use it.

This patch:

Introduce get_uts() and put_uts() (used later) and remove most of the special
cases for when UTS namespace is compiled in.

Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
  • Loading branch information
Eric W. Biederman authored and Linus Torvalds committed Dec 8, 2006
1 parent 6b1b60f commit cf9f151
Showing 1 changed file with 26 additions and 102 deletions.
128 changes: 26 additions & 102 deletions kernel/sysctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,28 @@ extern ctl_table inotify_table[];
int sysctl_legacy_va_layout;
#endif

static void *get_uts(ctl_table *table, int write)
{
char *which = table->data;
#ifdef CONFIG_UTS_NS
struct uts_namespace *uts_ns = current->nsproxy->uts_ns;
which = (which - (char *)&init_uts_ns) + (char *)uts_ns;
#endif
if (!write)
down_read(&uts_sem);
else
down_write(&uts_sem);
return which;
}

static void put_uts(ctl_table *table, int write, void *which)
{
if (!write)
up_read(&uts_sem);
else
up_write(&uts_sem);
}

/* /proc declarations: */

#ifdef CONFIG_PROC_SYSCTL
Expand Down Expand Up @@ -229,7 +251,6 @@ static ctl_table root_table[] = {
};

static ctl_table kern_table[] = {
#ifndef CONFIG_UTS_NS
{
.ctl_name = KERN_OSTYPE,
.procname = "ostype",
Expand Down Expand Up @@ -275,54 +296,6 @@ static ctl_table kern_table[] = {
.proc_handler = &proc_do_uts_string,
.strategy = &sysctl_string,
},
#else /* !CONFIG_UTS_NS */
{
.ctl_name = KERN_OSTYPE,
.procname = "ostype",
.data = NULL,
/* could maybe use __NEW_UTS_LEN here? */
.maxlen = FIELD_SIZEOF(struct new_utsname, sysname),
.mode = 0444,
.proc_handler = &proc_do_uts_string,
.strategy = &sysctl_string,
},
{
.ctl_name = KERN_OSRELEASE,
.procname = "osrelease",
.data = NULL,
.maxlen = FIELD_SIZEOF(struct new_utsname, release),
.mode = 0444,
.proc_handler = &proc_do_uts_string,
.strategy = &sysctl_string,
},
{
.ctl_name = KERN_VERSION,
.procname = "version",
.data = NULL,
.maxlen = FIELD_SIZEOF(struct new_utsname, version),
.mode = 0444,
.proc_handler = &proc_do_uts_string,
.strategy = &sysctl_string,
},
{
.ctl_name = KERN_NODENAME,
.procname = "hostname",
.data = NULL,
.maxlen = FIELD_SIZEOF(struct new_utsname, nodename),
.mode = 0644,
.proc_handler = &proc_do_uts_string,
.strategy = &sysctl_string,
},
{
.ctl_name = KERN_DOMAINNAME,
.procname = "domainname",
.data = NULL,
.maxlen = FIELD_SIZEOF(struct new_utsname, domainname),
.mode = 0644,
.proc_handler = &proc_do_uts_string,
.strategy = &sysctl_string,
},
#endif /* !CONFIG_UTS_NS */
{
.ctl_name = KERN_PANIC,
.procname = "panic",
Expand Down Expand Up @@ -1753,66 +1726,17 @@ int proc_dostring(ctl_table *table, int write, struct file *filp,
* Special case of dostring for the UTS structure. This has locks
* to observe. Should this be in kernel/sys.c ????
*/

#ifndef CONFIG_UTS_NS
static int proc_do_uts_string(ctl_table *table, int write, struct file *filp,
void __user *buffer, size_t *lenp, loff_t *ppos)
{
int r;

if (!write) {
down_read(&uts_sem);
r=proc_dostring(table,0,filp,buffer,lenp, ppos);
up_read(&uts_sem);
} else {
down_write(&uts_sem);
r=proc_dostring(table,1,filp,buffer,lenp, ppos);
up_write(&uts_sem);
}
return r;
}
#else /* !CONFIG_UTS_NS */
static int proc_do_uts_string(ctl_table *table, int write, struct file *filp,
void __user *buffer, size_t *lenp, loff_t *ppos)
{
int r;
struct uts_namespace* uts_ns = current->nsproxy->uts_ns;
char* which;

switch (table->ctl_name) {
case KERN_OSTYPE:
which = uts_ns->name.sysname;
break;
case KERN_NODENAME:
which = uts_ns->name.nodename;
break;
case KERN_OSRELEASE:
which = uts_ns->name.release;
break;
case KERN_VERSION:
which = uts_ns->name.version;
break;
case KERN_DOMAINNAME:
which = uts_ns->name.domainname;
break;
default:
r = -EINVAL;
goto out;
}

if (!write) {
down_read(&uts_sem);
r=_proc_do_string(which,table->maxlen,0,filp,buffer,lenp, ppos);
up_read(&uts_sem);
} else {
down_write(&uts_sem);
r=_proc_do_string(which,table->maxlen,1,filp,buffer,lenp, ppos);
up_write(&uts_sem);
}
out:
void *which;
which = get_uts(table, write);
r = _proc_do_string(which, table->maxlen,write,filp,buffer,lenp, ppos);
put_uts(table, write, which);
return r;
}
#endif /* !CONFIG_UTS_NS */

static int do_proc_dointvec_conv(int *negp, unsigned long *lvalp,
int *valp,
Expand Down

0 comments on commit cf9f151

Please sign in to comment.