From: ebiederm@xmission.com (Eric W. Biederman)
To: Earl Chew <echew@ixiacom.com>
Cc: Andrew Morton <akpm@linux-foundation.org>,
Ingo Molnar <mingo@elte.hu>,
Peter Zijlstra <a.p.zijlstra@chello.nl>,
Eric Paris <eparis@redhat.com>,
"Serge E. Hallyn" <serge.hallyn@canonical.com>,
"linux-kernel\@vger.kernel.org" <linux-kernel@vger.kernel.org>,
<adobriyan@gmail.com>
Subject: Re: [PATCH] Support single byte reads from integers published in procfs by kernel/sysctl.c
Date: Sun, 29 Jan 2012 16:15:10 -0800 [thread overview]
Message-ID: <m1ty3ekpv5.fsf@fess.ebiederm.org> (raw)
In-Reply-To: <4F25CEB5.8070704@ixiacom.com> (Earl Chew's message of "Sun, 29 Jan 2012 14:56:53 -0800")
Earl Chew <echew@ixiacom.com> writes:
>> If you are interested in fixing this properly with a tiny buffer
>> reachable from struct file I think this can be worth fixing. I think
>> this is doable by using seq_file in proc_sys_read.
>
> I've looked into making proc_sys_read() use seq_file, but there are a few
> issues to work through.
>
> I'm assuming that the existing kernel modules must continue to use the
> ctl_table/proc_dointvec/etc interface without requiring patching.
>
> The two main consequences of this are:
>
> a. The existing struct ctl_table interface should be preserved.
> Kernel modules use this to publish into procfs.
Generally. Changing all 200 or so users of the ctl_table interface is a
pain to audit and make certain you having done something silly.
> b. The existing proc_dointvec(), etc, functions must be preserved
> because they are exported via EXPORT_SYMBOL. Kernel modules
> may rely on these symbols in arbitrary ways.
You only have to worry about in kernel users, and a quick source audit
should allow to be certain that there are no arbitrary weird uses
of proc_dointvec.
> I tried use seq_file in proc_sys_read, and it comes close to solving
> the problem. The issue is that proc_dointvec() requires a __user pointer.
>
> A seq_file has an internal buffer that could be filled by proc_dointvec() -- but that
> seq_file buffer is in kernel space.
>
> This is not a problem isolated to the seq_file implementation. I think that
> any approach involving a small local buffer would mean that that buffer is
> in kernel space, and that buffer cannot be passed to proc_dointvec() as it
> stands now because proc_dointvec() requires a __user buffer.
We can definitely change the signature of proc_handler and thus
proc_dointvec and friends to be friendlier to an internal buffer.
For prototyping it probably makes sense to use set_fs so you can
use an internal buffer without needing to change the method.
> One approach that might work is to add a new field to struct ctl_table :
>
> struct ctl_table
> {
> ...
> proc_seq_handler *proc_seq_handler;
> };
>
> Existing modules can continue to use proc_dointvec() etc and fixed
> code can use the new proc_seq_handler interface using the new
> proc_seq_dointvec() etc.
>
>
> Although this preserves the old interface, it seems to me that this
> approach is flawed in that kernel modules using struct ctl_table and proc_dointvec()
> continue to be broken -- they are not fixed.
It might make a good intermediate transition scheme while existing
tables are being updated.
> So, perhaps breaking assumption (b) might be a reasonable thing to do ?
Definitely.
> If we accept that proc_dointvec() etc are only or mainly used in the
> context of filling out struct ctl_table, and that other kernel modules
> don't use proc_dointvec() in other contexts, then we can change the
> call signature of proc_dointvec() to stop using a __user pointer:
Exactly.
> 1. Change signature of proc_dointvec() etc to stop using __user pointer for reads
> 2. Change definition of typedef proc_call_handler to stop using __user pointer for reads
> 3. In kernel/sysctl.c don't use copy_to_user() for reads
All of which sound like nice cleanups, and likely to reduce the number
of places where people can badly get things wrong.
> Then proc_sys_read() can use proc_dointvec() etc to fill seq_file.
Yes. That sounds like a nice cleanup.
> For writes, the existing behaviour needs to be preserved. One approach
> that would solve this would be to add:
>
> union proc_buffer {
> void __user *uptr;
> void *kptr;
> };
>
> typedef int proc_handler (struct ctl_table *ctl, int write,
> union proc_buffer buffer, size_t *lenp, loff_t *ppos);
> I think this would be preferable to either casting away __user for reads, or
> adding two pointers to the proc_handler signature (one with __user, one without).
>
> If write is indicated, use buffer.uptr, and if not the handlers would use buffer.kptr.
For interface design I would look carefully at the bitmap interface that
comes out of sysctl. I think that is the most data interface we have.
I suspect what we want for writes is to read the existing value into an
internal buffer, and then allow partial writes to the internal buffer.
I don't know if writable seq_files exist.
> But this is not perfect. Kernel modules containing their _own_ proc_handler
> definitions would now be broken severely.
>
>
> And now I circle back to the proc_seq_handler approach. Each ctl_table client
> must be fixed individually (ie switch from proc_handler to proc_seq_handler).
>
> What do you think ?
It sounds like you are thinking things through well.
For a transition strategy we may want to change proc_handler into
operations structure instead of just a function pointer.
Only having a single method we can call sounds like a pain.
struct ctl_proc_operations {
int (*proc_handler)(....);
int (*proc_seq_handler)(...);
};
Or maybe:
struct ctl_proc_operations {
int (*proc_handler)(....);
int (*proc_seq_read_handler)(...);
int (*proc_seq_write_handler)(...);
};
Having the option of different read/write methods is a plus.
More usefully this should allow us to update what the implementation
of things like proc_dointvec mean without having to update all of
the tables. Which should make it much easier to preserve correctness,
because we don't a huge number of manual edits to ctl_table structures
all over the kernel.
Eric
next prev parent reply other threads:[~2012-01-30 0:12 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-01-22 18:46 [PATCH] Support single byte reads from integers published in procfs by kernel/sysctl.c Earl Chew
2012-01-23 14:47 ` Eric W. Biederman
2012-01-23 15:49 ` Earl Chew
2012-01-23 16:35 ` Eric W. Biederman
2012-01-23 16:43 ` Eric W. Biederman
2012-01-23 16:47 ` Earl Chew
2012-01-24 22:50 ` Andrew Morton
2012-01-25 6:28 ` Eric W. Biederman
2012-01-25 15:27 ` Earl Chew
2012-01-29 22:56 ` Earl Chew
2012-01-30 0:15 ` Eric W. Biederman [this message]
2012-01-30 1:13 ` Earl Chew
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=m1ty3ekpv5.fsf@fess.ebiederm.org \
--to=ebiederm@xmission.com \
--cc=a.p.zijlstra@chello.nl \
--cc=adobriyan@gmail.com \
--cc=akpm@linux-foundation.org \
--cc=echew@ixiacom.com \
--cc=eparis@redhat.com \
--cc=linux-kernel@vger.kernel.org \
--cc=mingo@elte.hu \
--cc=serge.hallyn@canonical.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.