signal/GenWQE: Fix sending of SIGKILL
authorEric W. Biederman <ebiederm@xmission.com>
Thu, 13 Sep 2018 09:28:01 +0000 (11:28 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 13 Nov 2018 19:16:57 +0000 (11:16 -0800)
commit 0ab93e9c99f8208c0a1a7b7170c827936268c996 upstream.

The genweq_add_file and genwqe_del_file by caching current without
using reference counting embed the assumption that a file descriptor
will never be passed from one process to another.  It even embeds the
assumption that the the thread that opened the file will be in
existence when the process terminates.   Neither of which are
guaranteed to be true.

Therefore replace caching the task_struct of the opener with
pid of the openers thread group id.  All the knowledge of the
opener is used for is as the target of SIGKILL and a SIGKILL
will kill the entire process group.

Rename genwqe_force_sig to genwqe_terminate, remove it's unncessary
signal argument, update it's ownly caller, and use kill_pid
instead of force_sig.

The work force_sig does in changing signal handling state is not
relevant to SIGKILL sent as SEND_SIG_PRIV.  The exact same processess
will be killed just with less work, and less confusion.  The work done
by force_sig is really only needed for handling syncrhonous
exceptions.

It will still be possible to cause genwqe_device_remove to wait
8 seconds by passing a file descriptor to another process but
the possible user after free is fixed.

Fixes: eaf4722d4645 ("GenWQE Character device and DDCB queue")
Cc: stable@vger.kernel.org
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Frank Haverkamp <haver@linux.vnet.ibm.com>
Cc: Joerg-Stephan Vogt <jsvogt@de.ibm.com>
Cc: Michael Jung <mijung@gmx.net>
Cc: Michael Ruettger <michael@ibmra.de>
Cc: Kleber Sacilotto de Souza <klebers@linux.vnet.ibm.com>
Cc: Sebastian Ott <sebott@linux.vnet.ibm.com>
Cc: Eberhard S. Amann <esa@linux.vnet.ibm.com>
Cc: Gabriel Krisman Bertazi <krisman@linux.vnet.ibm.com>
Cc: Guilherme G. Piccoli <gpiccoli@linux.vnet.ibm.com>
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/misc/genwqe/card_base.h
drivers/misc/genwqe/card_dev.c

index cb851c14ca4b17e52964647a1e3bbce5d6fb1ef9..159f35b2bd118e4a2a781b0ceafc8fe95b3e32df 100644 (file)
@@ -404,7 +404,7 @@ struct genwqe_file {
        struct file *filp;
 
        struct fasync_struct *async_queue;
-       struct task_struct *owner;
+       struct pid *opener;
        struct list_head list;          /* entry in list of open files */
 
        spinlock_t map_lock;            /* lock for dma_mappings */
index 7f1b282d7d963c65cf8a7a8bf5d7f559f668951e..c0012ca4229e1d8f406abace685205e27e6f07ad 100644 (file)
@@ -52,7 +52,7 @@ static void genwqe_add_file(struct genwqe_dev *cd, struct genwqe_file *cfile)
 {
        unsigned long flags;
 
-       cfile->owner = current;
+       cfile->opener = get_pid(task_tgid(current));
        spin_lock_irqsave(&cd->file_lock, flags);
        list_add(&cfile->list, &cd->file_list);
        spin_unlock_irqrestore(&cd->file_lock, flags);
@@ -65,6 +65,7 @@ static int genwqe_del_file(struct genwqe_dev *cd, struct genwqe_file *cfile)
        spin_lock_irqsave(&cd->file_lock, flags);
        list_del(&cfile->list);
        spin_unlock_irqrestore(&cd->file_lock, flags);
+       put_pid(cfile->opener);
 
        return 0;
 }
@@ -275,7 +276,7 @@ static int genwqe_kill_fasync(struct genwqe_dev *cd, int sig)
        return files;
 }
 
-static int genwqe_force_sig(struct genwqe_dev *cd, int sig)
+static int genwqe_terminate(struct genwqe_dev *cd)
 {
        unsigned int files = 0;
        unsigned long flags;
@@ -283,7 +284,7 @@ static int genwqe_force_sig(struct genwqe_dev *cd, int sig)
 
        spin_lock_irqsave(&cd->file_lock, flags);
        list_for_each_entry(cfile, &cd->file_list, list) {
-               force_sig(sig, cfile->owner);
+               kill_pid(cfile->opener, SIGKILL, 1);
                files++;
        }
        spin_unlock_irqrestore(&cd->file_lock, flags);
@@ -1356,7 +1357,7 @@ static int genwqe_inform_and_stop_processes(struct genwqe_dev *cd)
                dev_warn(&pci_dev->dev,
                         "[%s] send SIGKILL and wait ...\n", __func__);
 
-               rc = genwqe_force_sig(cd, SIGKILL); /* force terminate */
+               rc = genwqe_terminate(cd);
                if (rc) {
                        /* Give kill_timout more seconds to end processes */
                        for (i = 0; (i < genwqe_kill_timeout) &&