]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.11-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 6 Oct 2013 00:04:57 +0000 (17:04 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 6 Oct 2013 00:04:57 +0000 (17:04 -0700)
added patches:
cciss-fix-info-leak-in-cciss_ioctl32_passthru.patch
cpqarray-fix-info-leak-in-ida_locked_ioctl.patch
hid-fix-data-access-in-implement.patch
hid-fix-unused-rsize-usage.patch
nfsd4-fix-leak-of-inode-reference-on-delegation-failure.patch

queue-3.11/cciss-fix-info-leak-in-cciss_ioctl32_passthru.patch [new file with mode: 0644]
queue-3.11/cpqarray-fix-info-leak-in-ida_locked_ioctl.patch [new file with mode: 0644]
queue-3.11/hid-fix-data-access-in-implement.patch [new file with mode: 0644]
queue-3.11/hid-fix-unused-rsize-usage.patch [new file with mode: 0644]
queue-3.11/nfsd4-fix-leak-of-inode-reference-on-delegation-failure.patch [new file with mode: 0644]
queue-3.11/series [new file with mode: 0644]

diff --git a/queue-3.11/cciss-fix-info-leak-in-cciss_ioctl32_passthru.patch b/queue-3.11/cciss-fix-info-leak-in-cciss_ioctl32_passthru.patch
new file mode 100644 (file)
index 0000000..888d255
--- /dev/null
@@ -0,0 +1,35 @@
+From 58f09e00ae095e46ef9edfcf3a5fd9ccdfad065e Mon Sep 17 00:00:00 2001
+From: Dan Carpenter <dan.carpenter@oracle.com>
+Date: Tue, 24 Sep 2013 15:27:45 -0700
+Subject: cciss: fix info leak in cciss_ioctl32_passthru()
+
+From: Dan Carpenter <dan.carpenter@oracle.com>
+
+commit 58f09e00ae095e46ef9edfcf3a5fd9ccdfad065e upstream.
+
+The arg64 struct has a hole after ->buf_size which isn't cleared.  Or if
+any of the calls to copy_from_user() fail then that would cause an
+information leak as well.
+
+This was assigned CVE-2013-2147.
+
+Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
+Acked-by: Mike Miller <mike.miller@hp.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/block/cciss.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/block/cciss.c
++++ b/drivers/block/cciss.c
+@@ -1189,6 +1189,7 @@ static int cciss_ioctl32_passthru(struct
+       int err;
+       u32 cp;
++      memset(&arg64, 0, sizeof(arg64));
+       err = 0;
+       err |=
+           copy_from_user(&arg64.LUN_info, &arg32->LUN_info,
diff --git a/queue-3.11/cpqarray-fix-info-leak-in-ida_locked_ioctl.patch b/queue-3.11/cpqarray-fix-info-leak-in-ida_locked_ioctl.patch
new file mode 100644 (file)
index 0000000..c0199dc
--- /dev/null
@@ -0,0 +1,34 @@
+From 627aad1c01da6f881e7f98d71fd928ca0c316b1a Mon Sep 17 00:00:00 2001
+From: Dan Carpenter <dan.carpenter@oracle.com>
+Date: Tue, 24 Sep 2013 15:27:44 -0700
+Subject: cpqarray: fix info leak in ida_locked_ioctl()
+
+From: Dan Carpenter <dan.carpenter@oracle.com>
+
+commit 627aad1c01da6f881e7f98d71fd928ca0c316b1a upstream.
+
+The pciinfo struct has a two byte hole after ->dev_fn so stack
+information could be leaked to the user.
+
+This was assigned CVE-2013-2147.
+
+Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
+Acked-by: Mike Miller <mike.miller@hp.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/block/cpqarray.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/block/cpqarray.c
++++ b/drivers/block/cpqarray.c
+@@ -1193,6 +1193,7 @@ out_passthru:
+               ida_pci_info_struct pciinfo;
+               if (!arg) return -EINVAL;
++              memset(&pciinfo, 0, sizeof(pciinfo));
+               pciinfo.bus = host->pci_dev->bus->number;
+               pciinfo.dev_fn = host->pci_dev->devfn;
+               pciinfo.board_id = host->board_id;
diff --git a/queue-3.11/hid-fix-data-access-in-implement.patch b/queue-3.11/hid-fix-data-access-in-implement.patch
new file mode 100644 (file)
index 0000000..cda7e8a
--- /dev/null
@@ -0,0 +1,243 @@
+From 27ce405039bfe6d3f4143415c638f56a3df77dca Mon Sep 17 00:00:00 2001
+From: Jiri Kosina <jkosina@suse.cz>
+Date: Wed, 10 Jul 2013 19:56:27 +0200
+Subject: HID: fix data access in implement()
+
+From: Jiri Kosina <jkosina@suse.cz>
+
+commit 27ce405039bfe6d3f4143415c638f56a3df77dca upstream.
+
+implement() is setting bytes in LE data stream. In case the data is not
+aligned to 64bits, it reads past the allocated buffer. It doesn't really
+change any value there (it's properly bitmasked), but in case that this
+read past the boundary hits a page boundary, pagefault happens when
+accessing 64bits of 'x' in implement(), and kernel oopses.
+
+This happens much more often when numbered reports are in use, as the
+initial 8bit skip in the buffer makes the whole process work on values
+which are not aligned to 64bits.
+
+This problem dates back to attempts in 2005 and 2006 to make implement()
+and extract() as generic as possible, and even back then the problem
+was realized by Adam Kroperlin, but falsely assumed to be impossible
+to cause any harm:
+
+  http://www.mail-archive.com/linux-usb-devel@lists.sourceforge.net/msg47690.html
+
+I have made several attempts at fixing it "on the spot" directly in
+implement(), but the results were horrible; the special casing for processing
+last 64bit chunk and switching to different math makes it unreadable mess.
+
+I therefore took a path to allocate a few bytes more which will never make
+it into final report, but are there as a cushion for all the 64bit math
+operations happening in implement() and extract().
+
+All callers of hid_output_report() are converted at the same time to allocate
+the buffer by newly introduced hid_alloc_report_buf() helper.
+
+Bruno noticed that the whole raw_size test can be dropped as well, as
+hid_alloc_report_buf() makes sure that the buffer is always of a proper
+size.
+
+Reviewed-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
+Acked-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
+Signed-off-by: Jiri Kosina <jkosina@suse.cz>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/hid/hid-core.c            |   19 ++++++++++++++++++-
+ drivers/hid/hid-logitech-dj.c     |   12 ++++++++++--
+ drivers/hid/hid-picolcd_debugfs.c |   23 ++++++++++++-----------
+ drivers/hid/usbhid/hid-core.c     |    5 ++---
+ include/linux/hid.h               |    1 +
+ net/bluetooth/hidp/core.c         |   14 +++++++++-----
+ 6 files changed, 52 insertions(+), 22 deletions(-)
+
+--- a/drivers/hid/hid-core.c
++++ b/drivers/hid/hid-core.c
+@@ -1188,7 +1188,8 @@ static void hid_output_field(const struc
+ }
+ /*
+- * Create a report.
++ * Create a report. 'data' has to be allocated using
++ * hid_alloc_report_buf() so that it has proper size.
+  */
+ void hid_output_report(struct hid_report *report, __u8 *data)
+@@ -1205,6 +1206,22 @@ void hid_output_report(struct hid_report
+ EXPORT_SYMBOL_GPL(hid_output_report);
+ /*
++ * Allocator for buffer that is going to be passed to hid_output_report()
++ */
++u8 *hid_alloc_report_buf(struct hid_report *report, gfp_t flags)
++{
++      /*
++       * 7 extra bytes are necessary to achieve proper functionality
++       * of implement() working on 8 byte chunks
++       */
++
++      int len = ((report->size - 1) >> 3) + 1 + (report->id > 0) + 7;
++
++      return kmalloc(len, flags);
++}
++EXPORT_SYMBOL_GPL(hid_alloc_report_buf);
++
++/*
+  * Set a field value. The report this field belongs to has to be
+  * created and transferred to the device, to set this value in the
+  * device.
+--- a/drivers/hid/hid-logitech-dj.c
++++ b/drivers/hid/hid-logitech-dj.c
+@@ -619,7 +619,7 @@ static int logi_dj_ll_input_event(struct
+       struct hid_field *field;
+       struct hid_report *report;
+-      unsigned char data[8];
++      unsigned char *data;
+       int offset;
+       dbg_hid("%s: %s, type:%d | code:%d | value:%d\n",
+@@ -635,6 +635,13 @@ static int logi_dj_ll_input_event(struct
+               return -1;
+       }
+       hid_set_field(field, offset, value);
++
++      data = hid_alloc_report_buf(field->report, GFP_KERNEL);
++      if (!data) {
++              dev_warn(&dev->dev, "failed to allocate report buf memory\n");
++              return -1;
++      }
++
+       hid_output_report(field->report, &data[0]);
+       output_report_enum = &dj_rcv_hiddev->report_enum[HID_OUTPUT_REPORT];
+@@ -645,8 +652,9 @@ static int logi_dj_ll_input_event(struct
+       hid_hw_request(dj_rcv_hiddev, report, HID_REQ_SET_REPORT);
+-      return 0;
++      kfree(data);
++      return 0;
+ }
+ static int logi_dj_ll_start(struct hid_device *hid)
+--- a/drivers/hid/hid-picolcd_debugfs.c
++++ b/drivers/hid/hid-picolcd_debugfs.c
+@@ -394,7 +394,7 @@ static void dump_buff_as_hex(char *dst,
+ void picolcd_debug_out_report(struct picolcd_data *data,
+               struct hid_device *hdev, struct hid_report *report)
+ {
+-      u8 raw_data[70];
++      u8 *raw_data;
+       int raw_size = (report->size >> 3) + 1;
+       char *buff;
+ #define BUFF_SZ 256
+@@ -407,20 +407,20 @@ void picolcd_debug_out_report(struct pic
+       if (!buff)
+               return;
+-      snprintf(buff, BUFF_SZ, "\nout report %d (size %d) =  ",
+-                      report->id, raw_size);
+-      hid_debug_event(hdev, buff);
+-      if (raw_size + 5 > sizeof(raw_data)) {
++      raw_data = hid_alloc_report_buf(report, GFP_ATOMIC);
++      if (!raw_data) {
+               kfree(buff);
+-              hid_debug_event(hdev, " TOO BIG\n");
+               return;
+-      } else {
+-              raw_data[0] = report->id;
+-              hid_output_report(report, raw_data);
+-              dump_buff_as_hex(buff, BUFF_SZ, raw_data, raw_size);
+-              hid_debug_event(hdev, buff);
+       }
++      snprintf(buff, BUFF_SZ, "\nout report %d (size %d) =  ",
++                      report->id, raw_size);
++      hid_debug_event(hdev, buff);
++      raw_data[0] = report->id;
++      hid_output_report(report, raw_data);
++      dump_buff_as_hex(buff, BUFF_SZ, raw_data, raw_size);
++      hid_debug_event(hdev, buff);
++
+       switch (report->id) {
+       case REPORT_LED_STATE:
+               /* 1 data byte with GPO state */
+@@ -644,6 +644,7 @@ void picolcd_debug_out_report(struct pic
+               break;
+       }
+       wake_up_interruptible(&hdev->debug_wait);
++      kfree(raw_data);
+       kfree(buff);
+ }
+--- a/drivers/hid/usbhid/hid-core.c
++++ b/drivers/hid/usbhid/hid-core.c
+@@ -535,7 +535,6 @@ static void __usbhid_submit_report(struc
+ {
+       int head;
+       struct usbhid_device *usbhid = hid->driver_data;
+-      int len = ((report->size - 1) >> 3) + 1 + (report->id > 0);
+       if ((hid->quirks & HID_QUIRK_NOGET) && dir == USB_DIR_IN)
+               return;
+@@ -546,7 +545,7 @@ static void __usbhid_submit_report(struc
+                       return;
+               }
+-              usbhid->out[usbhid->outhead].raw_report = kmalloc(len, GFP_ATOMIC);
++              usbhid->out[usbhid->outhead].raw_report = hid_alloc_report_buf(report, GFP_ATOMIC);
+               if (!usbhid->out[usbhid->outhead].raw_report) {
+                       hid_warn(hid, "output queueing failed\n");
+                       return;
+@@ -595,7 +594,7 @@ static void __usbhid_submit_report(struc
+       }
+       if (dir == USB_DIR_OUT) {
+-              usbhid->ctrl[usbhid->ctrlhead].raw_report = kmalloc(len, GFP_ATOMIC);
++              usbhid->ctrl[usbhid->ctrlhead].raw_report = hid_alloc_report_buf(report, GFP_ATOMIC);
+               if (!usbhid->ctrl[usbhid->ctrlhead].raw_report) {
+                       hid_warn(hid, "control queueing failed\n");
+                       return;
+--- a/include/linux/hid.h
++++ b/include/linux/hid.h
+@@ -746,6 +746,7 @@ struct hid_field *hidinput_get_led_field
+ unsigned int hidinput_count_leds(struct hid_device *hid);
+ __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code);
+ void hid_output_report(struct hid_report *report, __u8 *data);
++u8 *hid_alloc_report_buf(struct hid_report *report, gfp_t flags);
+ struct hid_device *hid_allocate_device(void);
+ struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id);
+ int hid_parse_report(struct hid_device *hid, __u8 *start, unsigned size);
+--- a/net/bluetooth/hidp/core.c
++++ b/net/bluetooth/hidp/core.c
+@@ -225,17 +225,21 @@ static void hidp_input_report(struct hid
+ static int hidp_send_report(struct hidp_session *session, struct hid_report *report)
+ {
+-      unsigned char buf[32], hdr;
+-      int rsize;
++      unsigned char hdr;
++      u8 *buf;
++      int rsize, ret;
+-      rsize = ((report->size - 1) >> 3) + 1 + (report->id > 0);
+-      if (rsize > sizeof(buf))
++      buf = hid_alloc_report_buf(report, GFP_ATOMIC);
++      if (!buf)
+               return -EIO;
+       hid_output_report(report, buf);
+       hdr = HIDP_TRANS_DATA | HIDP_DATA_RTYPE_OUPUT;
+-      return hidp_send_intr_message(session, hdr, buf, rsize);
++      ret = hidp_send_intr_message(session, hdr, buf, rsize);
++
++      kfree(buf);
++      return ret;
+ }
+ static int hidp_get_raw_report(struct hid_device *hid,
diff --git a/queue-3.11/hid-fix-unused-rsize-usage.patch b/queue-3.11/hid-fix-unused-rsize-usage.patch
new file mode 100644 (file)
index 0000000..bd04565
--- /dev/null
@@ -0,0 +1,30 @@
+From bc197eedef1ae082ec662c64c3f4aa302821fb7a Mon Sep 17 00:00:00 2001
+From: Jiri Kosina <jkosina@suse.cz>
+Date: Mon, 22 Jul 2013 17:11:44 +0200
+Subject: HID: fix unused rsize usage
+
+From: Jiri Kosina <jkosina@suse.cz>
+
+commit bc197eedef1ae082ec662c64c3f4aa302821fb7a upstream.
+
+27ce4050 ("HID: fix data access in implement()") by mistake removed
+a setting of buffer size in hidp. Fix that by putting it back.
+
+Reported-by: kbuild test robot <fengguang.wu@intel.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.cz>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ net/bluetooth/hidp/core.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/net/bluetooth/hidp/core.c
++++ b/net/bluetooth/hidp/core.c
+@@ -236,6 +236,7 @@ static int hidp_send_report(struct hidp_
+       hid_output_report(report, buf);
+       hdr = HIDP_TRANS_DATA | HIDP_DATA_RTYPE_OUPUT;
++      rsize = ((report->size - 1) >> 3) + 1 + (report->id > 0);
+       ret = hidp_send_intr_message(session, hdr, buf, rsize);
+       kfree(buf);
diff --git a/queue-3.11/nfsd4-fix-leak-of-inode-reference-on-delegation-failure.patch b/queue-3.11/nfsd4-fix-leak-of-inode-reference-on-delegation-failure.patch
new file mode 100644 (file)
index 0000000..5d68d5a
--- /dev/null
@@ -0,0 +1,107 @@
+From bf7bd3e98be5c74813bee6ad496139fb0a011b3b Mon Sep 17 00:00:00 2001
+From: "J. Bruce Fields" <bfields@redhat.com>
+Date: Thu, 15 Aug 2013 16:55:26 -0400
+Subject: nfsd4: fix leak of inode reference on delegation failure
+
+From: "J. Bruce Fields" <bfields@redhat.com>
+
+commit bf7bd3e98be5c74813bee6ad496139fb0a011b3b upstream.
+
+This fixes a regression from 68a3396178e6688ad7367202cdf0af8ed03c8727
+"nfsd4: shut down more of delegation earlier".
+
+After that commit, nfs4_set_delegation() failures result in
+nfs4_put_delegation being called, but nfs4_put_delegation doesn't free
+the nfs4_file that has already been set by alloc_init_deleg().
+
+This can result in an oops on later unmounting the exported filesystem.
+
+Note also delaying the fi_had_conflict check we're able to return a
+better error (hence give 4.1 clients a better idea why the delegation
+failed; though note CONFLICT isn't an exact match here, as that's
+supposed to indicate a current conflict, but all we know here is that
+there was one recently).
+
+Reported-by: Toralf Förster <toralf.foerster@gmx.de>
+Tested-by: Toralf Förster <toralf.foerster@gmx.de>
+Signed-off-by: J. Bruce Fields <bfields@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/nfsd/nfs4state.c |   31 ++++++++++++++++++++-----------
+ 1 file changed, 20 insertions(+), 11 deletions(-)
+
+--- a/fs/nfsd/nfs4state.c
++++ b/fs/nfsd/nfs4state.c
+@@ -368,11 +368,8 @@ static struct nfs4_delegation *
+ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct svc_fh *current_fh)
+ {
+       struct nfs4_delegation *dp;
+-      struct nfs4_file *fp = stp->st_file;
+       dprintk("NFSD alloc_init_deleg\n");
+-      if (fp->fi_had_conflict)
+-              return NULL;
+       if (num_delegations > max_delegations)
+               return NULL;
+       dp = delegstateid(nfs4_alloc_stid(clp, deleg_slab));
+@@ -389,8 +386,7 @@ alloc_init_deleg(struct nfs4_client *clp
+       INIT_LIST_HEAD(&dp->dl_perfile);
+       INIT_LIST_HEAD(&dp->dl_perclnt);
+       INIT_LIST_HEAD(&dp->dl_recall_lru);
+-      get_nfs4_file(fp);
+-      dp->dl_file = fp;
++      dp->dl_file = NULL;
+       dp->dl_type = NFS4_OPEN_DELEGATE_READ;
+       fh_copy_shallow(&dp->dl_fh, &current_fh->fh_handle);
+       dp->dl_time = 0;
+@@ -3044,22 +3040,35 @@ static int nfs4_setlease(struct nfs4_del
+       return 0;
+ }
+-static int nfs4_set_delegation(struct nfs4_delegation *dp)
++static int nfs4_set_delegation(struct nfs4_delegation *dp, struct nfs4_file *fp)
+ {
+-      struct nfs4_file *fp = dp->dl_file;
++      int status;
+-      if (!fp->fi_lease)
+-              return nfs4_setlease(dp);
++      if (fp->fi_had_conflict)
++              return -EAGAIN;
++      get_nfs4_file(fp);
++      dp->dl_file = fp;
++      if (!fp->fi_lease) {
++              status = nfs4_setlease(dp);
++              if (status)
++                      goto out_free;
++              return 0;
++      }
+       spin_lock(&recall_lock);
+       if (fp->fi_had_conflict) {
+               spin_unlock(&recall_lock);
+-              return -EAGAIN;
++              status = -EAGAIN;
++              goto out_free;
+       }
+       atomic_inc(&fp->fi_delegees);
+       list_add(&dp->dl_perfile, &fp->fi_delegations);
+       spin_unlock(&recall_lock);
+       list_add(&dp->dl_perclnt, &dp->dl_stid.sc_client->cl_delegations);
+       return 0;
++out_free:
++      put_nfs4_file(fp);
++      dp->dl_file = fp;
++      return status;
+ }
+ static void nfsd4_open_deleg_none_ext(struct nfsd4_open *open, int status)
+@@ -3134,7 +3143,7 @@ nfs4_open_delegation(struct net *net, st
+       dp = alloc_init_deleg(oo->oo_owner.so_client, stp, fh);
+       if (dp == NULL)
+               goto out_no_deleg;
+-      status = nfs4_set_delegation(dp);
++      status = nfs4_set_delegation(dp, stp->st_file);
+       if (status)
+               goto out_free;
diff --git a/queue-3.11/series b/queue-3.11/series
new file mode 100644 (file)
index 0000000..ea86c23
--- /dev/null
@@ -0,0 +1,5 @@
+nfsd4-fix-leak-of-inode-reference-on-delegation-failure.patch
+cpqarray-fix-info-leak-in-ida_locked_ioctl.patch
+cciss-fix-info-leak-in-cciss_ioctl32_passthru.patch
+hid-fix-data-access-in-implement.patch
+hid-fix-unused-rsize-usage.patch