lkml.org 
[lkml]   [2012]   [Mar]   [30]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[ 118/175] sysctl: protect poll() in entries that may go away
    3.3-stable review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Lucas De Marchi <lucas.demarchi@profusion.mobi>

    commit 4e474a00d7ff746ed177ddae14fa8b2d4bad7a00 upstream.

    Protect code accessing ctl_table by grabbing the header with grab_header()
    and after releasing with sysctl_head_finish(). This is needed if poll()
    is called in entries created by modules: currently only hostname and
    domainname support poll(), but this bug may be triggered when/if modules
    use it and if user called poll() in a file that doesn't support it.

    Dave Jones reported the following when using a syscall fuzzer while
    hibernating/resuming:

    RIP: 0010:[<ffffffff81233e3e>] [<ffffffff81233e3e>] proc_sys_poll+0x4e/0x90
    RAX: 0000000000000145 RBX: ffff88020cab6940 RCX: 0000000000000000
    RDX: ffffffff81233df0 RSI: 6b6b6b6b6b6b6b6b RDI: ffff88020cab6940
    [ ... ]
    Code: 00 48 89 fb 48 89 f1 48 8b 40 30 4c 8b 60 e8 b8 45 01 00 00 49 83
    7c 24 28 00 74 2e 49 8b 74 24 30 48 85 f6 74 24 48 85 c9 75 32 <8b> 16
    b8 45 01 00 00 48 63 d2 49 39 d5 74 10 8b 06 48 98 48 89

    If an entry goes away while we are polling() it, ctl_table may not exist
    anymore.

    Reported-by: Dave Jones <davej@redhat.com>
    Signed-off-by: Lucas De Marchi <lucas.demarchi@profusion.mobi>
    Cc: Al Viro <viro@zeniv.linux.org.uk>
    Cc: Linus Torvalds <torvalds@linux-foundation.org>
    Cc: Alexey Dobriyan <adobriyan@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    fs/proc/proc_sysctl.c | 17 ++++++++++++++++-
    1 file changed, 16 insertions(+), 1 deletion(-)

    --- a/fs/proc/proc_sysctl.c
    +++ b/fs/proc/proc_sysctl.c
    @@ -188,20 +188,32 @@ static ssize_t proc_sys_write(struct fil

    static int proc_sys_open(struct inode *inode, struct file *filp)
    {
    + struct ctl_table_header *head = grab_header(inode);
    struct ctl_table *table = PROC_I(inode)->sysctl_entry;

    + /* sysctl was unregistered */
    + if (IS_ERR(head))
    + return PTR_ERR(head);
    +
    if (table->poll)
    filp->private_data = proc_sys_poll_event(table->poll);

    + sysctl_head_finish(head);
    +
    return 0;
    }

    static unsigned int proc_sys_poll(struct file *filp, poll_table *wait)
    {
    struct inode *inode = filp->f_path.dentry->d_inode;
    + struct ctl_table_header *head = grab_header(inode);
    struct ctl_table *table = PROC_I(inode)->sysctl_entry;
    - unsigned long event = (unsigned long)filp->private_data;
    unsigned int ret = DEFAULT_POLLMASK;
    + unsigned long event;
    +
    + /* sysctl was unregistered */
    + if (IS_ERR(head))
    + return POLLERR | POLLHUP;

    if (!table->proc_handler)
    goto out;
    @@ -209,6 +221,7 @@ static unsigned int proc_sys_poll(struct
    if (!table->poll)
    goto out;

    + event = (unsigned long)filp->private_data;
    poll_wait(filp, &table->poll->wait, wait);

    if (event != atomic_read(&table->poll->event)) {
    @@ -217,6 +230,8 @@ static unsigned int proc_sys_poll(struct
    }

    out:
    + sysctl_head_finish(head);
    +
    return ret;
    }




    \
     
     \ /
      Last update: 2012-03-30 23:29    [W:0.024 / U:124.680 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site