]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.19-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 6 Feb 2020 19:24:25 +0000 (20:24 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 6 Feb 2020 19:24:25 +0000 (20:24 +0100)
added patches:
acpi-battery-deal-better-with-neither-design-nor-full-capacity-not-being-reported.patch
acpi-battery-deal-with-design-or-full-capacity-being-reported-as-1.patch
acpi-battery-use-design-cap-for-capacity-calculations-if-full-cap-is-not-available.patch
acpi-video-do-not-export-a-non-working-backlight-interface-on-msi-ms-7721-boards.patch
alarmtimer-unregister-wakeup-source-when-module-get-fails.patch
crypto-geode-aes-convert-to-skcipher-api-and-make-thread-safe.patch
mmc-spi-toggle-spi-polarity-do-not-hardcode-it.patch
pci-tegra-fix-return-value-check-of-pm_runtime_get_sync.patch
ubifs-don-t-trigger-assertion-on-invalid-no-key-filename.patch
ubifs-fix-deadlock-in-concurrent-bulk-read-and-writepage.patch
ubifs-fix-fs_ioc_setflags-unexpectedly-clearing-encrypt-flag.patch
ubifs-reject-unsupported-ioctl-flags-explicitly.patch

14 files changed:
queue-4.19/acpi-battery-deal-better-with-neither-design-nor-full-capacity-not-being-reported.patch [new file with mode: 0644]
queue-4.19/acpi-battery-deal-with-design-or-full-capacity-being-reported-as-1.patch [new file with mode: 0644]
queue-4.19/acpi-battery-use-design-cap-for-capacity-calculations-if-full-cap-is-not-available.patch [new file with mode: 0644]
queue-4.19/acpi-video-do-not-export-a-non-working-backlight-interface-on-msi-ms-7721-boards.patch [new file with mode: 0644]
queue-4.19/alarmtimer-unregister-wakeup-source-when-module-get-fails.patch [new file with mode: 0644]
queue-4.19/crypto-geode-aes-convert-to-skcipher-api-and-make-thread-safe.patch [new file with mode: 0644]
queue-4.19/mmc-spi-toggle-spi-polarity-do-not-hardcode-it.patch [new file with mode: 0644]
queue-4.19/pci-tegra-fix-return-value-check-of-pm_runtime_get_sync.patch [new file with mode: 0644]
queue-4.19/series
queue-4.19/smb3-fix-signing-verification-of-large-reads.patch
queue-4.19/ubifs-don-t-trigger-assertion-on-invalid-no-key-filename.patch [new file with mode: 0644]
queue-4.19/ubifs-fix-deadlock-in-concurrent-bulk-read-and-writepage.patch [new file with mode: 0644]
queue-4.19/ubifs-fix-fs_ioc_setflags-unexpectedly-clearing-encrypt-flag.patch [new file with mode: 0644]
queue-4.19/ubifs-reject-unsupported-ioctl-flags-explicitly.patch [new file with mode: 0644]

diff --git a/queue-4.19/acpi-battery-deal-better-with-neither-design-nor-full-capacity-not-being-reported.patch b/queue-4.19/acpi-battery-deal-better-with-neither-design-nor-full-capacity-not-being-reported.patch
new file mode 100644 (file)
index 0000000..8572969
--- /dev/null
@@ -0,0 +1,115 @@
+From ff3154d1d89a2343fd5f82e65bc0cf1d4e6659b3 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Tue, 10 Dec 2019 10:57:52 +0100
+Subject: ACPI / battery: Deal better with neither design nor full capacity not being reported
+
+From: Hans de Goede <hdegoede@redhat.com>
+
+commit ff3154d1d89a2343fd5f82e65bc0cf1d4e6659b3 upstream.
+
+Commit b41901a2cf06 ("ACPI / battery: Do not export energy_full[_design] on
+devices without full_charge_capacity") added support for some (broken)
+devices which always report 0 for both design_capacity and
+full_charge_capacity.
+
+Since the device that commit was written as a fix for is not reporting any
+form of "full" capacity we cannot calculate the value for the
+POWER_SUPPLY_PROP_CAPACITY, this is worked around by using an alternative
+array of available properties which does not contain this property.
+
+This is necessary because userspace (upower) treats us returning -ENODEV
+as 0 and then typically will trigger an emergency shutdown because of that.
+Userspace does not do this if the capacity sysfs attribute is not present
+at all.
+
+There are two potential problems with that commit:
+ 1) It assumes that both full_charge- and design-capacity are broken at the
+    same time and only checks if full_charge- is broken.
+ 2) It assumes that this only ever happens for devices which report energy
+    units rather then charge units.
+
+This commit fixes both issues by only using the alternative
+array of available properties if both full_charge- and design-capacity are
+broken and by also adding an alternative array of available properties for
+devices using mA units.
+
+Fixes: b41901a2cf06 ("ACPI / battery: Do not export energy_full[_design] on devices without full_charge_capacity")
+Cc: 4.19+ <stable@vger.kernel.org> # 4.19+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/acpi/battery.c |   51 +++++++++++++++++++++++++++++++++++++------------
+ 1 file changed, 39 insertions(+), 12 deletions(-)
+
+--- a/drivers/acpi/battery.c
++++ b/drivers/acpi/battery.c
+@@ -355,6 +355,20 @@ static enum power_supply_property charge
+       POWER_SUPPLY_PROP_SERIAL_NUMBER,
+ };
++static enum power_supply_property charge_battery_full_cap_broken_props[] = {
++      POWER_SUPPLY_PROP_STATUS,
++      POWER_SUPPLY_PROP_PRESENT,
++      POWER_SUPPLY_PROP_TECHNOLOGY,
++      POWER_SUPPLY_PROP_CYCLE_COUNT,
++      POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
++      POWER_SUPPLY_PROP_VOLTAGE_NOW,
++      POWER_SUPPLY_PROP_CURRENT_NOW,
++      POWER_SUPPLY_PROP_CHARGE_NOW,
++      POWER_SUPPLY_PROP_MODEL_NAME,
++      POWER_SUPPLY_PROP_MANUFACTURER,
++      POWER_SUPPLY_PROP_SERIAL_NUMBER,
++};
++
+ static enum power_supply_property energy_battery_props[] = {
+       POWER_SUPPLY_PROP_STATUS,
+       POWER_SUPPLY_PROP_PRESENT,
+@@ -816,21 +830,34 @@ static void __exit battery_hook_exit(voi
+ static int sysfs_add_battery(struct acpi_battery *battery)
+ {
+       struct power_supply_config psy_cfg = { .drv_data = battery, };
++      bool full_cap_broken = false;
++
++      if (!ACPI_BATTERY_CAPACITY_VALID(battery->full_charge_capacity) &&
++          !ACPI_BATTERY_CAPACITY_VALID(battery->design_capacity))
++              full_cap_broken = true;
+       if (battery->power_unit == ACPI_BATTERY_POWER_UNIT_MA) {
+-              battery->bat_desc.properties = charge_battery_props;
+-              battery->bat_desc.num_properties =
+-                      ARRAY_SIZE(charge_battery_props);
+-      } else if (!ACPI_BATTERY_CAPACITY_VALID(
+-                                      battery->full_charge_capacity)) {
+-              battery->bat_desc.properties =
+-                      energy_battery_full_cap_broken_props;
+-              battery->bat_desc.num_properties =
+-                      ARRAY_SIZE(energy_battery_full_cap_broken_props);
++              if (full_cap_broken) {
++                      battery->bat_desc.properties =
++                          charge_battery_full_cap_broken_props;
++                      battery->bat_desc.num_properties =
++                          ARRAY_SIZE(charge_battery_full_cap_broken_props);
++              } else {
++                      battery->bat_desc.properties = charge_battery_props;
++                      battery->bat_desc.num_properties =
++                          ARRAY_SIZE(charge_battery_props);
++              }
+       } else {
+-              battery->bat_desc.properties = energy_battery_props;
+-              battery->bat_desc.num_properties =
+-                      ARRAY_SIZE(energy_battery_props);
++              if (full_cap_broken) {
++                      battery->bat_desc.properties =
++                          energy_battery_full_cap_broken_props;
++                      battery->bat_desc.num_properties =
++                          ARRAY_SIZE(energy_battery_full_cap_broken_props);
++              } else {
++                      battery->bat_desc.properties = energy_battery_props;
++                      battery->bat_desc.num_properties =
++                          ARRAY_SIZE(energy_battery_props);
++              }
+       }
+       battery->bat_desc.name = acpi_device_bid(battery->device);
diff --git a/queue-4.19/acpi-battery-deal-with-design-or-full-capacity-being-reported-as-1.patch b/queue-4.19/acpi-battery-deal-with-design-or-full-capacity-being-reported-as-1.patch
new file mode 100644 (file)
index 0000000..454028a
--- /dev/null
@@ -0,0 +1,96 @@
+From cc99f0ad52467028cb1251160f23ad4bb65baf20 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Tue, 10 Dec 2019 10:57:50 +0100
+Subject: ACPI / battery: Deal with design or full capacity being reported as -1
+
+From: Hans de Goede <hdegoede@redhat.com>
+
+commit cc99f0ad52467028cb1251160f23ad4bb65baf20 upstream.
+
+Commit b41901a2cf06 ("ACPI / battery: Do not export energy_full[_design]
+on devices without full_charge_capacity") added support for some (broken)
+devices which always report 0 for both design- and full_charge-capacity.
+
+This assumes that if the capacity is not being reported it is 0. The
+ThunderSoft TS178 tablet's _BIX implementation falsifies this assumption.
+It reports ACPI_BATTERY_VALUE_UNKNOWN (-1) as full_charge_capacity, which
+we treat as a valid value which causes several problems.
+
+This commit fixes this by adding a new ACPI_BATTERY_CAPACITY_VALID() helper
+which checks that the value is not 0 and not -1; and using this whenever we
+need to test if either design_capacity or full_charge_capacity is valid.
+
+Fixes: b41901a2cf06 ("ACPI / battery: Do not export energy_full[_design] on devices without full_charge_capacity")
+Cc: 4.19+ <stable@vger.kernel.org> # 4.19+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/acpi/battery.c |   19 ++++++++++++-------
+ 1 file changed, 12 insertions(+), 7 deletions(-)
+
+--- a/drivers/acpi/battery.c
++++ b/drivers/acpi/battery.c
+@@ -51,6 +51,8 @@
+ #define PREFIX "ACPI: "
+ #define ACPI_BATTERY_VALUE_UNKNOWN 0xFFFFFFFF
++#define ACPI_BATTERY_CAPACITY_VALID(capacity) \
++      ((capacity) != 0 && (capacity) != ACPI_BATTERY_VALUE_UNKNOWN)
+ #define ACPI_BATTERY_DEVICE_NAME      "Battery"
+@@ -205,7 +207,8 @@ static int acpi_battery_is_charged(struc
+ static bool acpi_battery_is_degraded(struct acpi_battery *battery)
+ {
+-      return battery->full_charge_capacity && battery->design_capacity &&
++      return ACPI_BATTERY_CAPACITY_VALID(battery->full_charge_capacity) &&
++              ACPI_BATTERY_CAPACITY_VALID(battery->design_capacity) &&
+               battery->full_charge_capacity < battery->design_capacity;
+ }
+@@ -276,14 +279,14 @@ static int acpi_battery_get_property(str
+               break;
+       case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
+       case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
+-              if (battery->design_capacity == ACPI_BATTERY_VALUE_UNKNOWN)
++              if (!ACPI_BATTERY_CAPACITY_VALID(battery->design_capacity))
+                       ret = -ENODEV;
+               else
+                       val->intval = battery->design_capacity * 1000;
+               break;
+       case POWER_SUPPLY_PROP_CHARGE_FULL:
+       case POWER_SUPPLY_PROP_ENERGY_FULL:
+-              if (battery->full_charge_capacity == ACPI_BATTERY_VALUE_UNKNOWN)
++              if (!ACPI_BATTERY_CAPACITY_VALID(battery->full_charge_capacity))
+                       ret = -ENODEV;
+               else
+                       val->intval = battery->full_charge_capacity * 1000;
+@@ -296,11 +299,12 @@ static int acpi_battery_get_property(str
+                       val->intval = battery->capacity_now * 1000;
+               break;
+       case POWER_SUPPLY_PROP_CAPACITY:
+-              if (battery->capacity_now && battery->full_charge_capacity)
++              if (battery->capacity_now == ACPI_BATTERY_VALUE_UNKNOWN ||
++                  !ACPI_BATTERY_CAPACITY_VALID(battery->full_charge_capacity))
++                      ret = -ENODEV;
++              else
+                       val->intval = battery->capacity_now * 100/
+                                       battery->full_charge_capacity;
+-              else
+-                      val->intval = 0;
+               break;
+       case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
+               if (battery->state & ACPI_BATTERY_STATE_CRITICAL)
+@@ -812,7 +816,8 @@ static int sysfs_add_battery(struct acpi
+               battery->bat_desc.properties = charge_battery_props;
+               battery->bat_desc.num_properties =
+                       ARRAY_SIZE(charge_battery_props);
+-      } else if (battery->full_charge_capacity == 0) {
++      } else if (!ACPI_BATTERY_CAPACITY_VALID(
++                                      battery->full_charge_capacity)) {
+               battery->bat_desc.properties =
+                       energy_battery_full_cap_broken_props;
+               battery->bat_desc.num_properties =
diff --git a/queue-4.19/acpi-battery-use-design-cap-for-capacity-calculations-if-full-cap-is-not-available.patch b/queue-4.19/acpi-battery-use-design-cap-for-capacity-calculations-if-full-cap-is-not-available.patch
new file mode 100644 (file)
index 0000000..c32cd1d
--- /dev/null
@@ -0,0 +1,65 @@
+From 5b74d1d16e2f5753fcbdecd6771b2d8370dda414 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Tue, 10 Dec 2019 10:57:51 +0100
+Subject: ACPI / battery: Use design-cap for capacity calculations if full-cap is not available
+
+From: Hans de Goede <hdegoede@redhat.com>
+
+commit 5b74d1d16e2f5753fcbdecd6771b2d8370dda414 upstream.
+
+The ThunderSoft TS178 tablet's _BIX implementation reports design_capacity
+but not full_charge_capacity.
+
+Before this commit this would cause us to return -ENODEV for the capacity
+attribute, which userspace does not like. Specifically upower does this:
+
+        if (sysfs_file_exists (native_path, "capacity")) {
+                percentage = sysfs_get_double (native_path, "capacity");
+
+Where the sysfs_get_double() helper returns 0 when we return -ENODEV,
+so the battery always reads 0% if we return -ENODEV.
+
+This commit fixes this by using the design-capacity instead of the
+full-charge-capacity when the full-charge-capacity is not available.
+
+Fixes: b41901a2cf06 ("ACPI / battery: Do not export energy_full[_design] on devices without full_charge_capacity")
+Cc: 4.19+ <stable@vger.kernel.org> # 4.19+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/acpi/battery.c |   11 ++++++++---
+ 1 file changed, 8 insertions(+), 3 deletions(-)
+
+--- a/drivers/acpi/battery.c
++++ b/drivers/acpi/battery.c
+@@ -230,7 +230,7 @@ static int acpi_battery_get_property(str
+                                    enum power_supply_property psp,
+                                    union power_supply_propval *val)
+ {
+-      int ret = 0;
++      int full_capacity = ACPI_BATTERY_VALUE_UNKNOWN, ret = 0;
+       struct acpi_battery *battery = to_acpi_battery(psy);
+       if (acpi_battery_present(battery)) {
+@@ -299,12 +299,17 @@ static int acpi_battery_get_property(str
+                       val->intval = battery->capacity_now * 1000;
+               break;
+       case POWER_SUPPLY_PROP_CAPACITY:
++              if (ACPI_BATTERY_CAPACITY_VALID(battery->full_charge_capacity))
++                      full_capacity = battery->full_charge_capacity;
++              else if (ACPI_BATTERY_CAPACITY_VALID(battery->design_capacity))
++                      full_capacity = battery->design_capacity;
++
+               if (battery->capacity_now == ACPI_BATTERY_VALUE_UNKNOWN ||
+-                  !ACPI_BATTERY_CAPACITY_VALID(battery->full_charge_capacity))
++                  full_capacity == ACPI_BATTERY_VALUE_UNKNOWN)
+                       ret = -ENODEV;
+               else
+                       val->intval = battery->capacity_now * 100/
+-                                      battery->full_charge_capacity;
++                                      full_capacity;
+               break;
+       case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
+               if (battery->state & ACPI_BATTERY_STATE_CRITICAL)
diff --git a/queue-4.19/acpi-video-do-not-export-a-non-working-backlight-interface-on-msi-ms-7721-boards.patch b/queue-4.19/acpi-video-do-not-export-a-non-working-backlight-interface-on-msi-ms-7721-boards.patch
new file mode 100644 (file)
index 0000000..5f72c56
--- /dev/null
@@ -0,0 +1,59 @@
+From d21a91629f4b8e794fc4c0e0c17c85cedf1d806c Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Tue, 17 Dec 2019 20:08:11 +0100
+Subject: ACPI: video: Do not export a non working backlight interface on MSI MS-7721 boards
+
+From: Hans de Goede <hdegoede@redhat.com>
+
+commit d21a91629f4b8e794fc4c0e0c17c85cedf1d806c upstream.
+
+Despite our heuristics to not wrongly export a non working ACPI backlight
+interface on desktop machines, we still end up exporting one on desktops
+using a motherboard from the MSI MS-7721 series.
+
+I've looked at improving the heuristics, but in this case a quirk seems
+to be the only way to solve this.
+
+While at it also add a comment to separate the video_detect_force_none
+entries in the video_detect_dmi_table from other type of entries, as we
+already do for the other entry types.
+
+Cc: All applicable <stable@vger.kernel.org>
+BugLink: https://bugzilla.redhat.com/show_bug.cgi?id=1783786
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/acpi/video_detect.c |   13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+--- a/drivers/acpi/video_detect.c
++++ b/drivers/acpi/video_detect.c
+@@ -328,6 +328,11 @@ static const struct dmi_system_id video_
+               DMI_MATCH(DMI_PRODUCT_NAME, "Precision 7510"),
+               },
+       },
++
++      /*
++       * Desktops which falsely report a backlight and which our heuristics
++       * for this do not catch.
++       */
+       {
+        .callback = video_detect_force_none,
+        .ident = "Dell OptiPlex 9020M",
+@@ -336,6 +341,14 @@ static const struct dmi_system_id video_
+               DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 9020M"),
+               },
+       },
++      {
++       .callback = video_detect_force_none,
++       .ident = "MSI MS-7721",
++       .matches = {
++              DMI_MATCH(DMI_SYS_VENDOR, "MSI"),
++              DMI_MATCH(DMI_PRODUCT_NAME, "MS-7721"),
++              },
++      },
+       { },
+ };
diff --git a/queue-4.19/alarmtimer-unregister-wakeup-source-when-module-get-fails.patch b/queue-4.19/alarmtimer-unregister-wakeup-source-when-module-get-fails.patch
new file mode 100644 (file)
index 0000000..8a01b5d
--- /dev/null
@@ -0,0 +1,64 @@
+From 6b6d188aae79a630957aefd88ff5c42af6553ee3 Mon Sep 17 00:00:00 2001
+From: Stephen Boyd <swboyd@chromium.org>
+Date: Thu, 9 Jan 2020 07:59:07 -0800
+Subject: alarmtimer: Unregister wakeup source when module get fails
+
+From: Stephen Boyd <swboyd@chromium.org>
+
+commit 6b6d188aae79a630957aefd88ff5c42af6553ee3 upstream.
+
+The alarmtimer_rtc_add_device() function creates a wakeup source and then
+tries to grab a module reference. If that fails the function returns early
+with an error code, but fails to remove the wakeup source.
+
+Cleanup this exit path so there is no dangling wakeup source, which is
+named 'alarmtime' left allocated which will conflict with another RTC
+device that may be registered later.
+
+Fixes: 51218298a25e ("alarmtimer: Ensure RTC module is not unloaded")
+Signed-off-by: Stephen Boyd <swboyd@chromium.org>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Reviewed-by: Douglas Anderson <dianders@chromium.org>
+Cc: stable@vger.kernel.org
+Link: https://lore.kernel.org/r/20200109155910.907-2-swboyd@chromium.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ kernel/time/alarmtimer.c |    8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+--- a/kernel/time/alarmtimer.c
++++ b/kernel/time/alarmtimer.c
+@@ -91,6 +91,7 @@ static int alarmtimer_rtc_add_device(str
+       unsigned long flags;
+       struct rtc_device *rtc = to_rtc_device(dev);
+       struct wakeup_source *__ws;
++      int ret = 0;
+       if (rtcdev)
+               return -EBUSY;
+@@ -105,8 +106,8 @@ static int alarmtimer_rtc_add_device(str
+       spin_lock_irqsave(&rtcdev_lock, flags);
+       if (!rtcdev) {
+               if (!try_module_get(rtc->owner)) {
+-                      spin_unlock_irqrestore(&rtcdev_lock, flags);
+-                      return -1;
++                      ret = -1;
++                      goto unlock;
+               }
+               rtcdev = rtc;
+@@ -115,11 +116,12 @@ static int alarmtimer_rtc_add_device(str
+               ws = __ws;
+               __ws = NULL;
+       }
++unlock:
+       spin_unlock_irqrestore(&rtcdev_lock, flags);
+       wakeup_source_unregister(__ws);
+-      return 0;
++      return ret;
+ }
+ static inline void alarmtimer_rtc_timer_init(void)
diff --git a/queue-4.19/crypto-geode-aes-convert-to-skcipher-api-and-make-thread-safe.patch b/queue-4.19/crypto-geode-aes-convert-to-skcipher-api-and-make-thread-safe.patch
new file mode 100644 (file)
index 0000000..929d6b9
--- /dev/null
@@ -0,0 +1,705 @@
+From 4549f7e5aa27ffc2cba63b5db8842a3b486f5688 Mon Sep 17 00:00:00 2001
+From: Eric Biggers <ebiggers@google.com>
+Date: Thu, 10 Oct 2019 21:51:32 -0700
+Subject: crypto: geode-aes - convert to skcipher API and make thread-safe
+
+From: Eric Biggers <ebiggers@google.com>
+
+commit 4549f7e5aa27ffc2cba63b5db8842a3b486f5688 upstream.
+
+The geode AES driver is heavily broken because it stores per-request
+state in the transform context.  So it will crash or produce the wrong
+result if used by any of the many places in the kernel that issue
+concurrent requests for the same transform object.
+
+This driver is also implemented using the deprecated blkcipher API,
+which makes it difficult to fix, and puts it among the drivers
+preventing that API from being removed.
+
+Convert this driver to use the skcipher API, and change it to not store
+per-request state in the transform context.
+
+Fixes: 9fe757b0cfce ("[PATCH] crypto: Add support for the Geode LX AES hardware")
+Signed-off-by: Eric Biggers <ebiggers@google.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Florian Bezdeka <florian@bezdeka.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/crypto/geode-aes.c |  450 +++++++++++++++------------------------------
+ drivers/crypto/geode-aes.h |   15 -
+ 2 files changed, 153 insertions(+), 312 deletions(-)
+
+--- a/drivers/crypto/geode-aes.c
++++ b/drivers/crypto/geode-aes.c
+@@ -14,7 +14,7 @@
+ #include <linux/spinlock.h>
+ #include <crypto/algapi.h>
+ #include <crypto/aes.h>
+-#include <crypto/skcipher.h>
++#include <crypto/internal/skcipher.h>
+ #include <linux/io.h>
+ #include <linux/delay.h>
+@@ -28,12 +28,12 @@ static spinlock_t lock;
+ /* Write a 128 bit field (either a writable key or IV) */
+ static inline void
+-_writefield(u32 offset, void *value)
++_writefield(u32 offset, const void *value)
+ {
+       int i;
+       for (i = 0; i < 4; i++)
+-              iowrite32(((u32 *) value)[i], _iobase + offset + (i * 4));
++              iowrite32(((const u32 *) value)[i], _iobase + offset + (i * 4));
+ }
+ /* Read a 128 bit field (either a writable key or IV) */
+@@ -47,12 +47,12 @@ _readfield(u32 offset, void *value)
+ }
+ static int
+-do_crypt(void *src, void *dst, int len, u32 flags)
++do_crypt(const void *src, void *dst, u32 len, u32 flags)
+ {
+       u32 status;
+       u32 counter = AES_OP_TIMEOUT;
+-      iowrite32(virt_to_phys(src), _iobase + AES_SOURCEA_REG);
++      iowrite32(virt_to_phys((void *)src), _iobase + AES_SOURCEA_REG);
+       iowrite32(virt_to_phys(dst), _iobase + AES_DSTA_REG);
+       iowrite32(len,  _iobase + AES_LENA_REG);
+@@ -69,16 +69,14 @@ do_crypt(void *src, void *dst, int len,
+       return counter ? 0 : 1;
+ }
+-static unsigned int
+-geode_aes_crypt(struct geode_aes_op *op)
++static void
++geode_aes_crypt(const struct geode_aes_tfm_ctx *tctx, const void *src,
++              void *dst, u32 len, u8 *iv, int mode, int dir)
+ {
+       u32 flags = 0;
+       unsigned long iflags;
+       int ret;
+-      if (op->len == 0)
+-              return 0;
+-
+       /* If the source and destination is the same, then
+        * we need to turn on the coherent flags, otherwise
+        * we don't need to worry
+@@ -86,32 +84,28 @@ geode_aes_crypt(struct geode_aes_op *op)
+       flags |= (AES_CTRL_DCA | AES_CTRL_SCA);
+-      if (op->dir == AES_DIR_ENCRYPT)
++      if (dir == AES_DIR_ENCRYPT)
+               flags |= AES_CTRL_ENCRYPT;
+       /* Start the critical section */
+       spin_lock_irqsave(&lock, iflags);
+-      if (op->mode == AES_MODE_CBC) {
++      if (mode == AES_MODE_CBC) {
+               flags |= AES_CTRL_CBC;
+-              _writefield(AES_WRITEIV0_REG, op->iv);
++              _writefield(AES_WRITEIV0_REG, iv);
+       }
+-      if (!(op->flags & AES_FLAGS_HIDDENKEY)) {
+-              flags |= AES_CTRL_WRKEY;
+-              _writefield(AES_WRITEKEY0_REG, op->key);
+-      }
++      flags |= AES_CTRL_WRKEY;
++      _writefield(AES_WRITEKEY0_REG, tctx->key);
+-      ret = do_crypt(op->src, op->dst, op->len, flags);
++      ret = do_crypt(src, dst, len, flags);
+       BUG_ON(ret);
+-      if (op->mode == AES_MODE_CBC)
+-              _readfield(AES_WRITEIV0_REG, op->iv);
++      if (mode == AES_MODE_CBC)
++              _readfield(AES_WRITEIV0_REG, iv);
+       spin_unlock_irqrestore(&lock, iflags);
+-
+-      return op->len;
+ }
+ /* CRYPTO-API Functions */
+@@ -119,13 +113,13 @@ geode_aes_crypt(struct geode_aes_op *op)
+ static int geode_setkey_cip(struct crypto_tfm *tfm, const u8 *key,
+               unsigned int len)
+ {
+-      struct geode_aes_op *op = crypto_tfm_ctx(tfm);
++      struct geode_aes_tfm_ctx *tctx = crypto_tfm_ctx(tfm);
+       unsigned int ret;
+-      op->keylen = len;
++      tctx->keylen = len;
+       if (len == AES_KEYSIZE_128) {
+-              memcpy(op->key, key, len);
++              memcpy(tctx->key, key, len);
+               return 0;
+       }
+@@ -138,132 +132,93 @@ static int geode_setkey_cip(struct crypt
+       /*
+        * The requested key size is not supported by HW, do a fallback
+        */
+-      op->fallback.cip->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK;
+-      op->fallback.cip->base.crt_flags |= (tfm->crt_flags & CRYPTO_TFM_REQ_MASK);
++      tctx->fallback.cip->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK;
++      tctx->fallback.cip->base.crt_flags |=
++              (tfm->crt_flags & CRYPTO_TFM_REQ_MASK);
+-      ret = crypto_cipher_setkey(op->fallback.cip, key, len);
++      ret = crypto_cipher_setkey(tctx->fallback.cip, key, len);
+       if (ret) {
+               tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK;
+-              tfm->crt_flags |= (op->fallback.cip->base.crt_flags & CRYPTO_TFM_RES_MASK);
++              tfm->crt_flags |= (tctx->fallback.cip->base.crt_flags &
++                                 CRYPTO_TFM_RES_MASK);
+       }
+       return ret;
+ }
+-static int geode_setkey_blk(struct crypto_tfm *tfm, const u8 *key,
+-              unsigned int len)
++static int geode_setkey_skcipher(struct crypto_skcipher *tfm, const u8 *key,
++                               unsigned int len)
+ {
+-      struct geode_aes_op *op = crypto_tfm_ctx(tfm);
++      struct geode_aes_tfm_ctx *tctx = crypto_skcipher_ctx(tfm);
+       unsigned int ret;
+-      op->keylen = len;
++      tctx->keylen = len;
+       if (len == AES_KEYSIZE_128) {
+-              memcpy(op->key, key, len);
++              memcpy(tctx->key, key, len);
+               return 0;
+       }
+       if (len != AES_KEYSIZE_192 && len != AES_KEYSIZE_256) {
+               /* not supported at all */
+-              tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
++              crypto_skcipher_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
+               return -EINVAL;
+       }
+       /*
+        * The requested key size is not supported by HW, do a fallback
+        */
+-      crypto_skcipher_clear_flags(op->fallback.blk, CRYPTO_TFM_REQ_MASK);
+-      crypto_skcipher_set_flags(op->fallback.blk,
+-                                tfm->crt_flags & CRYPTO_TFM_REQ_MASK);
+-
+-      ret = crypto_skcipher_setkey(op->fallback.blk, key, len);
+-      if (ret) {
+-              tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK;
+-              tfm->crt_flags |= crypto_skcipher_get_flags(op->fallback.blk) &
+-                                CRYPTO_TFM_RES_MASK;
+-      }
++      crypto_skcipher_clear_flags(tctx->fallback.skcipher,
++                                  CRYPTO_TFM_REQ_MASK);
++      crypto_skcipher_set_flags(tctx->fallback.skcipher,
++                                crypto_skcipher_get_flags(tfm) &
++                                CRYPTO_TFM_REQ_MASK);
++      ret = crypto_skcipher_setkey(tctx->fallback.skcipher, key, len);
++      crypto_skcipher_set_flags(tfm,
++                                crypto_skcipher_get_flags(tctx->fallback.skcipher) &
++                                CRYPTO_TFM_RES_MASK);
+       return ret;
+ }
+-static int fallback_blk_dec(struct blkcipher_desc *desc,
+-              struct scatterlist *dst, struct scatterlist *src,
+-              unsigned int nbytes)
+-{
+-      struct geode_aes_op *op = crypto_blkcipher_ctx(desc->tfm);
+-      SKCIPHER_REQUEST_ON_STACK(req, op->fallback.blk);
+-
+-      skcipher_request_set_tfm(req, op->fallback.blk);
+-      skcipher_request_set_callback(req, 0, NULL, NULL);
+-      skcipher_request_set_crypt(req, src, dst, nbytes, desc->info);
+-
+-      return crypto_skcipher_decrypt(req);
+-}
+-
+-static int fallback_blk_enc(struct blkcipher_desc *desc,
+-              struct scatterlist *dst, struct scatterlist *src,
+-              unsigned int nbytes)
+-{
+-      struct geode_aes_op *op = crypto_blkcipher_ctx(desc->tfm);
+-      SKCIPHER_REQUEST_ON_STACK(req, op->fallback.blk);
+-
+-      skcipher_request_set_tfm(req, op->fallback.blk);
+-      skcipher_request_set_callback(req, 0, NULL, NULL);
+-      skcipher_request_set_crypt(req, src, dst, nbytes, desc->info);
+-
+-      return crypto_skcipher_encrypt(req);
+-}
+-
+ static void
+ geode_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
+ {
+-      struct geode_aes_op *op = crypto_tfm_ctx(tfm);
++      const struct geode_aes_tfm_ctx *tctx = crypto_tfm_ctx(tfm);
+-      if (unlikely(op->keylen != AES_KEYSIZE_128)) {
+-              crypto_cipher_encrypt_one(op->fallback.cip, out, in);
++      if (unlikely(tctx->keylen != AES_KEYSIZE_128)) {
++              crypto_cipher_encrypt_one(tctx->fallback.cip, out, in);
+               return;
+       }
+-      op->src = (void *) in;
+-      op->dst = (void *) out;
+-      op->mode = AES_MODE_ECB;
+-      op->flags = 0;
+-      op->len = AES_BLOCK_SIZE;
+-      op->dir = AES_DIR_ENCRYPT;
+-
+-      geode_aes_crypt(op);
++      geode_aes_crypt(tctx, in, out, AES_BLOCK_SIZE, NULL,
++                      AES_MODE_ECB, AES_DIR_ENCRYPT);
+ }
+ static void
+ geode_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
+ {
+-      struct geode_aes_op *op = crypto_tfm_ctx(tfm);
++      const struct geode_aes_tfm_ctx *tctx = crypto_tfm_ctx(tfm);
+-      if (unlikely(op->keylen != AES_KEYSIZE_128)) {
+-              crypto_cipher_decrypt_one(op->fallback.cip, out, in);
++      if (unlikely(tctx->keylen != AES_KEYSIZE_128)) {
++              crypto_cipher_decrypt_one(tctx->fallback.cip, out, in);
+               return;
+       }
+-      op->src = (void *) in;
+-      op->dst = (void *) out;
+-      op->mode = AES_MODE_ECB;
+-      op->flags = 0;
+-      op->len = AES_BLOCK_SIZE;
+-      op->dir = AES_DIR_DECRYPT;
+-
+-      geode_aes_crypt(op);
++      geode_aes_crypt(tctx, in, out, AES_BLOCK_SIZE, NULL,
++                      AES_MODE_ECB, AES_DIR_DECRYPT);
+ }
+ static int fallback_init_cip(struct crypto_tfm *tfm)
+ {
+       const char *name = crypto_tfm_alg_name(tfm);
+-      struct geode_aes_op *op = crypto_tfm_ctx(tfm);
++      struct geode_aes_tfm_ctx *tctx = crypto_tfm_ctx(tfm);
+-      op->fallback.cip = crypto_alloc_cipher(name, 0,
+-                              CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK);
++      tctx->fallback.cip = crypto_alloc_cipher(name, 0,
++                                               CRYPTO_ALG_NEED_FALLBACK);
+-      if (IS_ERR(op->fallback.cip)) {
++      if (IS_ERR(tctx->fallback.cip)) {
+               printk(KERN_ERR "Error allocating fallback algo %s\n", name);
+-              return PTR_ERR(op->fallback.cip);
++              return PTR_ERR(tctx->fallback.cip);
+       }
+       return 0;
+@@ -271,10 +226,9 @@ static int fallback_init_cip(struct cryp
+ static void fallback_exit_cip(struct crypto_tfm *tfm)
+ {
+-      struct geode_aes_op *op = crypto_tfm_ctx(tfm);
++      struct geode_aes_tfm_ctx *tctx = crypto_tfm_ctx(tfm);
+-      crypto_free_cipher(op->fallback.cip);
+-      op->fallback.cip = NULL;
++      crypto_free_cipher(tctx->fallback.cip);
+ }
+ static struct crypto_alg geode_alg = {
+@@ -287,7 +241,7 @@ static struct crypto_alg geode_alg = {
+       .cra_init                       =       fallback_init_cip,
+       .cra_exit                       =       fallback_exit_cip,
+       .cra_blocksize          =       AES_BLOCK_SIZE,
+-      .cra_ctxsize            =       sizeof(struct geode_aes_op),
++      .cra_ctxsize            =       sizeof(struct geode_aes_tfm_ctx),
+       .cra_module                     =       THIS_MODULE,
+       .cra_u                          =       {
+               .cipher =       {
+@@ -300,222 +254,126 @@ static struct crypto_alg geode_alg = {
+       }
+ };
+-static int
+-geode_cbc_decrypt(struct blkcipher_desc *desc,
+-                struct scatterlist *dst, struct scatterlist *src,
+-                unsigned int nbytes)
+-{
+-      struct geode_aes_op *op = crypto_blkcipher_ctx(desc->tfm);
+-      struct blkcipher_walk walk;
+-      int err, ret;
+-
+-      if (nbytes % AES_BLOCK_SIZE)
+-              return -EINVAL;
+-
+-      if (unlikely(op->keylen != AES_KEYSIZE_128))
+-              return fallback_blk_dec(desc, dst, src, nbytes);
+-
+-      blkcipher_walk_init(&walk, dst, src, nbytes);
+-      err = blkcipher_walk_virt(desc, &walk);
+-      op->iv = walk.iv;
+-
+-      while ((nbytes = walk.nbytes)) {
+-              op->src = walk.src.virt.addr,
+-              op->dst = walk.dst.virt.addr;
+-              op->mode = AES_MODE_CBC;
+-              op->len = nbytes - (nbytes % AES_BLOCK_SIZE);
+-              op->dir = AES_DIR_DECRYPT;
+-
+-              ret = geode_aes_crypt(op);
+-
+-              nbytes -= ret;
+-              err = blkcipher_walk_done(desc, &walk, nbytes);
+-      }
+-
+-      return err;
+-}
+-
+-static int
+-geode_cbc_encrypt(struct blkcipher_desc *desc,
+-                struct scatterlist *dst, struct scatterlist *src,
+-                unsigned int nbytes)
+-{
+-      struct geode_aes_op *op = crypto_blkcipher_ctx(desc->tfm);
+-      struct blkcipher_walk walk;
+-      int err, ret;
+-
+-      if (nbytes % AES_BLOCK_SIZE)
+-              return -EINVAL;
+-
+-      if (unlikely(op->keylen != AES_KEYSIZE_128))
+-              return fallback_blk_enc(desc, dst, src, nbytes);
+-
+-      blkcipher_walk_init(&walk, dst, src, nbytes);
+-      err = blkcipher_walk_virt(desc, &walk);
+-      op->iv = walk.iv;
+-
+-      while ((nbytes = walk.nbytes)) {
+-              op->src = walk.src.virt.addr,
+-              op->dst = walk.dst.virt.addr;
+-              op->mode = AES_MODE_CBC;
+-              op->len = nbytes - (nbytes % AES_BLOCK_SIZE);
+-              op->dir = AES_DIR_ENCRYPT;
+-
+-              ret = geode_aes_crypt(op);
+-              nbytes -= ret;
+-              err = blkcipher_walk_done(desc, &walk, nbytes);
+-      }
+-
+-      return err;
+-}
+-
+-static int fallback_init_blk(struct crypto_tfm *tfm)
++static int geode_init_skcipher(struct crypto_skcipher *tfm)
+ {
+-      const char *name = crypto_tfm_alg_name(tfm);
+-      struct geode_aes_op *op = crypto_tfm_ctx(tfm);
+-
+-      op->fallback.blk = crypto_alloc_skcipher(name, 0,
+-                                               CRYPTO_ALG_ASYNC |
+-                                               CRYPTO_ALG_NEED_FALLBACK);
++      const char *name = crypto_tfm_alg_name(&tfm->base);
++      struct geode_aes_tfm_ctx *tctx = crypto_skcipher_ctx(tfm);
+-      if (IS_ERR(op->fallback.blk)) {
++      tctx->fallback.skcipher =
++              crypto_alloc_skcipher(name, 0, CRYPTO_ALG_NEED_FALLBACK |
++                                    CRYPTO_ALG_ASYNC);
++      if (IS_ERR(tctx->fallback.skcipher)) {
+               printk(KERN_ERR "Error allocating fallback algo %s\n", name);
+-              return PTR_ERR(op->fallback.blk);
++              return PTR_ERR(tctx->fallback.skcipher);
+       }
++      crypto_skcipher_set_reqsize(tfm, sizeof(struct skcipher_request) +
++                                  crypto_skcipher_reqsize(tctx->fallback.skcipher));
+       return 0;
+ }
+-static void fallback_exit_blk(struct crypto_tfm *tfm)
++static void geode_exit_skcipher(struct crypto_skcipher *tfm)
+ {
+-      struct geode_aes_op *op = crypto_tfm_ctx(tfm);
++      struct geode_aes_tfm_ctx *tctx = crypto_skcipher_ctx(tfm);
+-      crypto_free_skcipher(op->fallback.blk);
+-      op->fallback.blk = NULL;
++      crypto_free_skcipher(tctx->fallback.skcipher);
+ }
+-static struct crypto_alg geode_cbc_alg = {
+-      .cra_name               =       "cbc(aes)",
+-      .cra_driver_name        =       "cbc-aes-geode",
+-      .cra_priority           =       400,
+-      .cra_flags                      =       CRYPTO_ALG_TYPE_BLKCIPHER |
+-                                              CRYPTO_ALG_KERN_DRIVER_ONLY |
+-                                              CRYPTO_ALG_NEED_FALLBACK,
+-      .cra_init                       =       fallback_init_blk,
+-      .cra_exit                       =       fallback_exit_blk,
+-      .cra_blocksize          =       AES_BLOCK_SIZE,
+-      .cra_ctxsize            =       sizeof(struct geode_aes_op),
+-      .cra_alignmask          =       15,
+-      .cra_type                       =       &crypto_blkcipher_type,
+-      .cra_module                     =       THIS_MODULE,
+-      .cra_u                          =       {
+-              .blkcipher      =       {
+-                      .min_keysize    =       AES_MIN_KEY_SIZE,
+-                      .max_keysize    =       AES_MAX_KEY_SIZE,
+-                      .setkey                 =       geode_setkey_blk,
+-                      .encrypt                =       geode_cbc_encrypt,
+-                      .decrypt                =       geode_cbc_decrypt,
+-                      .ivsize                 =       AES_BLOCK_SIZE,
+-              }
+-      }
+-};
+-
+-static int
+-geode_ecb_decrypt(struct blkcipher_desc *desc,
+-                struct scatterlist *dst, struct scatterlist *src,
+-                unsigned int nbytes)
+-{
+-      struct geode_aes_op *op = crypto_blkcipher_ctx(desc->tfm);
+-      struct blkcipher_walk walk;
+-      int err, ret;
++static int geode_skcipher_crypt(struct skcipher_request *req, int mode, int dir)
++{
++      struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
++      const struct geode_aes_tfm_ctx *tctx = crypto_skcipher_ctx(tfm);
++      struct skcipher_walk walk;
++      unsigned int nbytes;
++      int err;
+-      if (nbytes % AES_BLOCK_SIZE)
+-              return -EINVAL;
++      if (unlikely(tctx->keylen != AES_KEYSIZE_128)) {
++              struct skcipher_request *subreq = skcipher_request_ctx(req);
+-      if (unlikely(op->keylen != AES_KEYSIZE_128))
+-              return fallback_blk_dec(desc, dst, src, nbytes);
++              *subreq = *req;
++              skcipher_request_set_tfm(subreq, tctx->fallback.skcipher);
++              if (dir == AES_DIR_DECRYPT)
++                      return crypto_skcipher_decrypt(subreq);
++              else
++                      return crypto_skcipher_encrypt(subreq);
++      }
+-      blkcipher_walk_init(&walk, dst, src, nbytes);
+-      err = blkcipher_walk_virt(desc, &walk);
++      err = skcipher_walk_virt(&walk, req, false);
+-      while ((nbytes = walk.nbytes)) {
+-              op->src = walk.src.virt.addr,
+-              op->dst = walk.dst.virt.addr;
+-              op->mode = AES_MODE_ECB;
+-              op->len = nbytes - (nbytes % AES_BLOCK_SIZE);
+-              op->dir = AES_DIR_DECRYPT;
+-
+-              ret = geode_aes_crypt(op);
+-              nbytes -= ret;
+-              err = blkcipher_walk_done(desc, &walk, nbytes);
++      while ((nbytes = walk.nbytes) != 0) {
++              geode_aes_crypt(tctx, walk.src.virt.addr, walk.dst.virt.addr,
++                              round_down(nbytes, AES_BLOCK_SIZE),
++                              walk.iv, mode, dir);
++              err = skcipher_walk_done(&walk, nbytes % AES_BLOCK_SIZE);
+       }
+       return err;
+ }
+-static int
+-geode_ecb_encrypt(struct blkcipher_desc *desc,
+-                struct scatterlist *dst, struct scatterlist *src,
+-                unsigned int nbytes)
+-{
+-      struct geode_aes_op *op = crypto_blkcipher_ctx(desc->tfm);
+-      struct blkcipher_walk walk;
+-      int err, ret;
+-
+-      if (nbytes % AES_BLOCK_SIZE)
+-              return -EINVAL;
+-
+-      if (unlikely(op->keylen != AES_KEYSIZE_128))
+-              return fallback_blk_enc(desc, dst, src, nbytes);
+-
+-      blkcipher_walk_init(&walk, dst, src, nbytes);
+-      err = blkcipher_walk_virt(desc, &walk);
+-
+-      while ((nbytes = walk.nbytes)) {
+-              op->src = walk.src.virt.addr,
+-              op->dst = walk.dst.virt.addr;
+-              op->mode = AES_MODE_ECB;
+-              op->len = nbytes - (nbytes % AES_BLOCK_SIZE);
+-              op->dir = AES_DIR_ENCRYPT;
+-
+-              ret = geode_aes_crypt(op);
+-              nbytes -= ret;
+-              ret =  blkcipher_walk_done(desc, &walk, nbytes);
+-      }
++static int geode_cbc_encrypt(struct skcipher_request *req)
++{
++      return geode_skcipher_crypt(req, AES_MODE_CBC, AES_DIR_ENCRYPT);
++}
+-      return err;
++static int geode_cbc_decrypt(struct skcipher_request *req)
++{
++      return geode_skcipher_crypt(req, AES_MODE_CBC, AES_DIR_DECRYPT);
+ }
+-static struct crypto_alg geode_ecb_alg = {
+-      .cra_name                       =       "ecb(aes)",
+-      .cra_driver_name        =       "ecb-aes-geode",
+-      .cra_priority           =       400,
+-      .cra_flags                      =       CRYPTO_ALG_TYPE_BLKCIPHER |
+-                                              CRYPTO_ALG_KERN_DRIVER_ONLY |
+-                                              CRYPTO_ALG_NEED_FALLBACK,
+-      .cra_init                       =       fallback_init_blk,
+-      .cra_exit                       =       fallback_exit_blk,
+-      .cra_blocksize          =       AES_BLOCK_SIZE,
+-      .cra_ctxsize            =       sizeof(struct geode_aes_op),
+-      .cra_alignmask          =       15,
+-      .cra_type                       =       &crypto_blkcipher_type,
+-      .cra_module                     =       THIS_MODULE,
+-      .cra_u                          =       {
+-              .blkcipher      =       {
+-                      .min_keysize    =       AES_MIN_KEY_SIZE,
+-                      .max_keysize    =       AES_MAX_KEY_SIZE,
+-                      .setkey                 =       geode_setkey_blk,
+-                      .encrypt                =       geode_ecb_encrypt,
+-                      .decrypt                =       geode_ecb_decrypt,
+-              }
+-      }
++static int geode_ecb_encrypt(struct skcipher_request *req)
++{
++      return geode_skcipher_crypt(req, AES_MODE_ECB, AES_DIR_ENCRYPT);
++}
++
++static int geode_ecb_decrypt(struct skcipher_request *req)
++{
++      return geode_skcipher_crypt(req, AES_MODE_ECB, AES_DIR_DECRYPT);
++}
++
++static struct skcipher_alg geode_skcipher_algs[] = {
++      {
++              .base.cra_name          = "cbc(aes)",
++              .base.cra_driver_name   = "cbc-aes-geode",
++              .base.cra_priority      = 400,
++              .base.cra_flags         = CRYPTO_ALG_KERN_DRIVER_ONLY |
++                                        CRYPTO_ALG_NEED_FALLBACK,
++              .base.cra_blocksize     = AES_BLOCK_SIZE,
++              .base.cra_ctxsize       = sizeof(struct geode_aes_tfm_ctx),
++              .base.cra_alignmask     = 15,
++              .base.cra_module        = THIS_MODULE,
++              .init                   = geode_init_skcipher,
++              .exit                   = geode_exit_skcipher,
++              .setkey                 = geode_setkey_skcipher,
++              .encrypt                = geode_cbc_encrypt,
++              .decrypt                = geode_cbc_decrypt,
++              .min_keysize            = AES_MIN_KEY_SIZE,
++              .max_keysize            = AES_MAX_KEY_SIZE,
++              .ivsize                 = AES_BLOCK_SIZE,
++      }, {
++              .base.cra_name          = "ecb(aes)",
++              .base.cra_driver_name   = "ecb-aes-geode",
++              .base.cra_priority      = 400,
++              .base.cra_flags         = CRYPTO_ALG_KERN_DRIVER_ONLY |
++                                        CRYPTO_ALG_NEED_FALLBACK,
++              .base.cra_blocksize     = AES_BLOCK_SIZE,
++              .base.cra_ctxsize       = sizeof(struct geode_aes_tfm_ctx),
++              .base.cra_alignmask     = 15,
++              .base.cra_module        = THIS_MODULE,
++              .init                   = geode_init_skcipher,
++              .exit                   = geode_exit_skcipher,
++              .setkey                 = geode_setkey_skcipher,
++              .encrypt                = geode_ecb_encrypt,
++              .decrypt                = geode_ecb_decrypt,
++              .min_keysize            = AES_MIN_KEY_SIZE,
++              .max_keysize            = AES_MAX_KEY_SIZE,
++      },
+ };
+ static void geode_aes_remove(struct pci_dev *dev)
+ {
+       crypto_unregister_alg(&geode_alg);
+-      crypto_unregister_alg(&geode_ecb_alg);
+-      crypto_unregister_alg(&geode_cbc_alg);
++      crypto_unregister_skciphers(geode_skcipher_algs,
++                                  ARRAY_SIZE(geode_skcipher_algs));
+       pci_iounmap(dev, _iobase);
+       _iobase = NULL;
+@@ -553,20 +411,14 @@ static int geode_aes_probe(struct pci_de
+       if (ret)
+               goto eiomap;
+-      ret = crypto_register_alg(&geode_ecb_alg);
++      ret = crypto_register_skciphers(geode_skcipher_algs,
++                                      ARRAY_SIZE(geode_skcipher_algs));
+       if (ret)
+               goto ealg;
+-      ret = crypto_register_alg(&geode_cbc_alg);
+-      if (ret)
+-              goto eecb;
+-
+       dev_notice(&dev->dev, "GEODE AES engine enabled.\n");
+       return 0;
+- eecb:
+-      crypto_unregister_alg(&geode_ecb_alg);
+-
+  ealg:
+       crypto_unregister_alg(&geode_alg);
+--- a/drivers/crypto/geode-aes.h
++++ b/drivers/crypto/geode-aes.h
+@@ -50,21 +50,10 @@
+ #define AES_OP_TIMEOUT    0x50000
+-struct geode_aes_op {
+-
+-      void *src;
+-      void *dst;
+-
+-      u32 mode;
+-      u32 dir;
+-      u32 flags;
+-      int len;
+-
++struct geode_aes_tfm_ctx {
+       u8 key[AES_KEYSIZE_128];
+-      u8 *iv;
+-
+       union {
+-              struct crypto_skcipher *blk;
++              struct crypto_skcipher *skcipher;
+               struct crypto_cipher *cip;
+       } fallback;
+       u32 keylen;
diff --git a/queue-4.19/mmc-spi-toggle-spi-polarity-do-not-hardcode-it.patch b/queue-4.19/mmc-spi-toggle-spi-polarity-do-not-hardcode-it.patch
new file mode 100644 (file)
index 0000000..7adc9bf
--- /dev/null
@@ -0,0 +1,64 @@
+From af3ed119329cf9690598c5a562d95dfd128e91d6 Mon Sep 17 00:00:00 2001
+From: Linus Walleij <linus.walleij@linaro.org>
+Date: Wed, 4 Dec 2019 16:27:49 +0100
+Subject: mmc: spi: Toggle SPI polarity, do not hardcode it
+
+From: Linus Walleij <linus.walleij@linaro.org>
+
+commit af3ed119329cf9690598c5a562d95dfd128e91d6 upstream.
+
+The code in mmc_spi_initsequence() tries to send a burst with
+high chipselect and for this reason hardcodes the device into
+SPI_CS_HIGH.
+
+This is not good because the SPI_CS_HIGH flag indicates
+logical "asserted" CS not always the physical level. In
+some cases the signal is inverted in the GPIO library and
+in that case SPI_CS_HIGH is already set, and enforcing
+SPI_CS_HIGH again will actually drive it low.
+
+Instead of hard-coding this, toggle the polarity so if the
+default is LOW it goes high to assert chipselect but if it
+is already high then toggle it low instead.
+
+Cc: Phil Elwell <phil@raspberrypi.org>
+Reported-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+Reviewed-by: Mark Brown <broonie@kernel.org>
+Link: https://lore.kernel.org/r/20191204152749.12652-1-linus.walleij@linaro.org
+Cc: stable@vger.kernel.org
+Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/mmc/host/mmc_spi.c |   11 ++++++++---
+ 1 file changed, 8 insertions(+), 3 deletions(-)
+
+--- a/drivers/mmc/host/mmc_spi.c
++++ b/drivers/mmc/host/mmc_spi.c
+@@ -1154,17 +1154,22 @@ static void mmc_spi_initsequence(struct
+        * SPI protocol.  Another is that when chipselect is released while
+        * the card returns BUSY status, the clock must issue several cycles
+        * with chipselect high before the card will stop driving its output.
++       *
++       * SPI_CS_HIGH means "asserted" here. In some cases like when using
++       * GPIOs for chip select, SPI_CS_HIGH is set but this will be logically
++       * inverted by gpiolib, so if we want to ascertain to drive it high
++       * we should toggle the default with an XOR as we do here.
+        */
+-      host->spi->mode |= SPI_CS_HIGH;
++      host->spi->mode ^= SPI_CS_HIGH;
+       if (spi_setup(host->spi) != 0) {
+               /* Just warn; most cards work without it. */
+               dev_warn(&host->spi->dev,
+                               "can't change chip-select polarity\n");
+-              host->spi->mode &= ~SPI_CS_HIGH;
++              host->spi->mode ^= SPI_CS_HIGH;
+       } else {
+               mmc_spi_readbytes(host, 18);
+-              host->spi->mode &= ~SPI_CS_HIGH;
++              host->spi->mode ^= SPI_CS_HIGH;
+               if (spi_setup(host->spi) != 0) {
+                       /* Wot, we can't get the same setup we had before? */
+                       dev_err(&host->spi->dev,
diff --git a/queue-4.19/pci-tegra-fix-return-value-check-of-pm_runtime_get_sync.patch b/queue-4.19/pci-tegra-fix-return-value-check-of-pm_runtime_get_sync.patch
new file mode 100644 (file)
index 0000000..ba4f1f8
--- /dev/null
@@ -0,0 +1,38 @@
+From 885199148442f56b880995d703d2ed03b6481a3c Mon Sep 17 00:00:00 2001
+From: David Engraf <david.engraf@sysgo.com>
+Date: Mon, 16 Dec 2019 12:18:25 +0100
+Subject: PCI: tegra: Fix return value check of pm_runtime_get_sync()
+
+From: David Engraf <david.engraf@sysgo.com>
+
+commit 885199148442f56b880995d703d2ed03b6481a3c upstream.
+
+pm_runtime_get_sync() returns the device's usage counter. This might
+be >0 if the device is already powered up or CONFIG_PM is disabled.
+
+Abort probe function on real error only.
+
+Fixes: da76ba50963b ("PCI: tegra: Add power management support")
+Link: https://lore.kernel.org/r/20191216111825.28136-1-david.engraf@sysgo.com
+Signed-off-by: David Engraf <david.engraf@sysgo.com>
+Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
+Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+Acked-by: Andrew Murray <andrew.murray@arm.com>
+Cc: stable@vger.kernel.org     # v4.17+
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/pci/controller/pci-tegra.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/pci/controller/pci-tegra.c
++++ b/drivers/pci/controller/pci-tegra.c
+@@ -2398,7 +2398,7 @@ static int tegra_pcie_probe(struct platf
+       pm_runtime_enable(pcie->dev);
+       err = pm_runtime_get_sync(pcie->dev);
+-      if (err) {
++      if (err < 0) {
+               dev_err(dev, "fail to enable pcie controller: %d\n", err);
+               goto teardown_msi;
+       }
index f6078346e3b49b74e21bb4ac2d88a42727cff859..2c355ec4cddd6bd4c271b59207514befa1790ed8 100644 (file)
@@ -54,3 +54,15 @@ s390-mm-fix-dynamic-pagetable-upgrade-for-hugetlbfs.patch
 powerpc-xmon-don-t-access-asdr-in-vms.patch
 powerpc-pseries-advance-pfn-if-section-is-not-present-in-lmb_is_removable.patch
 smb3-fix-signing-verification-of-large-reads.patch
+crypto-geode-aes-convert-to-skcipher-api-and-make-thread-safe.patch
+pci-tegra-fix-return-value-check-of-pm_runtime_get_sync.patch
+mmc-spi-toggle-spi-polarity-do-not-hardcode-it.patch
+acpi-video-do-not-export-a-non-working-backlight-interface-on-msi-ms-7721-boards.patch
+acpi-battery-deal-with-design-or-full-capacity-being-reported-as-1.patch
+acpi-battery-use-design-cap-for-capacity-calculations-if-full-cap-is-not-available.patch
+acpi-battery-deal-better-with-neither-design-nor-full-capacity-not-being-reported.patch
+alarmtimer-unregister-wakeup-source-when-module-get-fails.patch
+ubifs-reject-unsupported-ioctl-flags-explicitly.patch
+ubifs-don-t-trigger-assertion-on-invalid-no-key-filename.patch
+ubifs-fix-fs_ioc_setflags-unexpectedly-clearing-encrypt-flag.patch
+ubifs-fix-deadlock-in-concurrent-bulk-read-and-writepage.patch
index f066c2dfaf7a1fde07e3306eb305bd2e161a54a3..5239a29920b944185e5d03aa8f3b2eea4ff6ace5 100644 (file)
@@ -22,14 +22,12 @@ Signed-off-by: Steve French <stfrench@microsoft.com>
 Reviewed-by: Ronnie Sahlberg <lsahlber@redhat.com>
 Signed-off-by: Sasha Levin <sashal@kernel.org>
 ---
- fs/cifs/smb2pdu.c | 4 ++--
+ fs/cifs/smb2pdu.c |    4 ++--
  1 file changed, 2 insertions(+), 2 deletions(-)
 
-diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
-index 43f29621e51ff..93ef1d8e82c75 100644
 --- a/fs/cifs/smb2pdu.c
 +++ b/fs/cifs/smb2pdu.c
-@@ -3130,8 +3130,8 @@ smb2_readv_callback(struct mid_q_entry *mid)
+@@ -3130,8 +3130,8 @@ smb2_readv_callback(struct mid_q_entry *
        struct smb2_sync_hdr *shdr =
                                (struct smb2_sync_hdr *)rdata->iov[0].iov_base;
        unsigned int credits_received = 0;
@@ -40,6 +38,3 @@ index 43f29621e51ff..93ef1d8e82c75 100644
                                 .rq_pages = rdata->pages,
                                 .rq_offset = rdata->page_offset,
                                 .rq_npages = rdata->nr_pages,
--- 
-2.20.1
-
diff --git a/queue-4.19/ubifs-don-t-trigger-assertion-on-invalid-no-key-filename.patch b/queue-4.19/ubifs-don-t-trigger-assertion-on-invalid-no-key-filename.patch
new file mode 100644 (file)
index 0000000..992fe1f
--- /dev/null
@@ -0,0 +1,49 @@
+From f0d07a98a070bb5e443df19c3aa55693cbca9341 Mon Sep 17 00:00:00 2001
+From: Eric Biggers <ebiggers@google.com>
+Date: Mon, 20 Jan 2020 14:31:59 -0800
+Subject: ubifs: don't trigger assertion on invalid no-key filename
+
+From: Eric Biggers <ebiggers@google.com>
+
+commit f0d07a98a070bb5e443df19c3aa55693cbca9341 upstream.
+
+If userspace provides an invalid fscrypt no-key filename which encodes a
+hash value with any of the UBIFS node type bits set (i.e. the high 3
+bits), gracefully report ENOENT rather than triggering ubifs_assert().
+
+Test case with kvm-xfstests shell:
+
+    . fs/ubifs/config
+    . ~/xfstests/common/encrypt
+    dev=$(__blkdev_to_ubi_volume /dev/vdc)
+    ubiupdatevol $dev -t
+    mount $dev /mnt -t ubifs
+    mkdir /mnt/edir
+    xfs_io -c set_encpolicy /mnt/edir
+    rm /mnt/edir/_,,,,,DAAAAAAAAAAAAAAAAAAAAAAAAAA
+
+With the bug, the following assertion fails on the 'rm' command:
+
+    [   19.066048] UBIFS error (ubi0:0 pid 379): ubifs_assert_failed: UBIFS assert failed: !(hash & ~UBIFS_S_KEY_HASH_MASK), in fs/ubifs/key.h:170
+
+Fixes: f4f61d2cc6d8 ("ubifs: Implement encrypted filenames")
+Cc: <stable@vger.kernel.org> # v4.10+
+Link: https://lore.kernel.org/r/20200120223201.241390-5-ebiggers@kernel.org
+Signed-off-by: Eric Biggers <ebiggers@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/ubifs/dir.c |    2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/fs/ubifs/dir.c
++++ b/fs/ubifs/dir.c
+@@ -242,6 +242,8 @@ static struct dentry *ubifs_lookup(struc
+       if (nm.hash) {
+               ubifs_assert(c, fname_len(&nm) == 0);
+               ubifs_assert(c, fname_name(&nm) == NULL);
++              if (nm.hash & ~UBIFS_S_KEY_HASH_MASK)
++                      goto done; /* ENOENT */
+               dent_key_init_hash(c, &key, dir->i_ino, nm.hash);
+               err = ubifs_tnc_lookup_dh(c, &key, dent, nm.minor_hash);
+       } else {
diff --git a/queue-4.19/ubifs-fix-deadlock-in-concurrent-bulk-read-and-writepage.patch b/queue-4.19/ubifs-fix-deadlock-in-concurrent-bulk-read-and-writepage.patch
new file mode 100644 (file)
index 0000000..546deb0
--- /dev/null
@@ -0,0 +1,59 @@
+From f5de5b83303e61b1f3fb09bd77ce3ac2d7a475f2 Mon Sep 17 00:00:00 2001
+From: Zhihao Cheng <chengzhihao1@huawei.com>
+Date: Sat, 11 Jan 2020 17:50:36 +0800
+Subject: ubifs: Fix deadlock in concurrent bulk-read and writepage
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Zhihao Cheng <chengzhihao1@huawei.com>
+
+commit f5de5b83303e61b1f3fb09bd77ce3ac2d7a475f2 upstream.
+
+In ubifs, concurrent execution of writepage and bulk read on the same file
+may cause ABBA deadlock, for example (Reproduce method see Link):
+
+Process A(Bulk-read starts from page4)         Process B(write page4 back)
+  vfs_read                                       wb_workfn or fsync
+  ...                                            ...
+  generic_file_buffered_read                     write_cache_pages
+    ubifs_readpage                                 LOCK(page4)
+
+      ubifs_bulk_read                              ubifs_writepage
+        LOCK(ui->ui_mutex)                           ubifs_write_inode
+
+         ubifs_do_bulk_read                           LOCK(ui->ui_mutex)
+           find_or_create_page(alloc page4)                  ↑
+             LOCK(page4)                   <--     ABBA deadlock occurs!
+
+In order to ensure the serialization execution of bulk read, we can't
+remove the big lock 'ui->ui_mutex' in ubifs_bulk_read(). Instead, we
+allow ubifs_do_bulk_read() to lock page failed by replacing
+find_or_create_page(FGP_LOCK) with
+pagecache_get_page(FGP_LOCK | FGP_NOWAIT).
+
+Signed-off-by: Zhihao Cheng <chengzhihao1@huawei.com>
+Suggested-by: zhangyi (F) <yi.zhang@huawei.com>
+Cc: <Stable@vger.kernel.org>
+Fixes: 4793e7c5e1c ("UBIFS: add bulk-read facility")
+Link: https://bugzilla.kernel.org/show_bug.cgi?id=206153
+Signed-off-by: Richard Weinberger <richard@nod.at>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/ubifs/file.c |    4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+--- a/fs/ubifs/file.c
++++ b/fs/ubifs/file.c
+@@ -798,7 +798,9 @@ static int ubifs_do_bulk_read(struct ubi
+               if (page_offset > end_index)
+                       break;
+-              page = find_or_create_page(mapping, page_offset, ra_gfp_mask);
++              page = pagecache_get_page(mapping, page_offset,
++                               FGP_LOCK|FGP_ACCESSED|FGP_CREAT|FGP_NOWAIT,
++                               ra_gfp_mask);
+               if (!page)
+                       break;
+               if (!PageUptodate(page))
diff --git a/queue-4.19/ubifs-fix-fs_ioc_setflags-unexpectedly-clearing-encrypt-flag.patch b/queue-4.19/ubifs-fix-fs_ioc_setflags-unexpectedly-clearing-encrypt-flag.patch
new file mode 100644 (file)
index 0000000..3d58ae8
--- /dev/null
@@ -0,0 +1,57 @@
+From 2b57067a7778484c10892fa191997bfda29fea13 Mon Sep 17 00:00:00 2001
+From: Eric Biggers <ebiggers@google.com>
+Date: Mon, 9 Dec 2019 14:23:24 -0800
+Subject: ubifs: Fix FS_IOC_SETFLAGS unexpectedly clearing encrypt flag
+
+From: Eric Biggers <ebiggers@google.com>
+
+commit 2b57067a7778484c10892fa191997bfda29fea13 upstream.
+
+UBIFS's implementation of FS_IOC_SETFLAGS fails to preserve existing
+inode flags that aren't settable by FS_IOC_SETFLAGS, namely the encrypt
+flag.  This causes the encrypt flag to be unexpectedly cleared.
+
+Fix it by preserving existing unsettable flags, like ext4 and f2fs do.
+
+Test case with kvm-xfstests shell:
+
+    FSTYP=ubifs KEYCTL_PROG=keyctl
+    . fs/ubifs/config
+    . ~/xfstests/common/encrypt
+    dev=$(__blkdev_to_ubi_volume /dev/vdc)
+    ubiupdatevol -t $dev
+    mount $dev /mnt -t ubifs
+    k=$(_generate_session_encryption_key)
+    mkdir /mnt/edir
+    xfs_io -c "set_encpolicy $k" /mnt/edir
+    echo contents > /mnt/edir/file
+    chattr +i /mnt/edir/file
+    chattr -i /mnt/edir/file
+
+With the bug, the following errors occur on the last command:
+
+    [   18.081559] fscrypt (ubifs, inode 67): Inconsistent encryption context (parent directory: 65)
+    chattr: Operation not permitted while reading flags on /mnt/edir/file
+
+Fixes: d475a507457b ("ubifs: Add skeleton for fscrypto")
+Cc: <stable@vger.kernel.org> # v4.10+
+Signed-off-by: Eric Biggers <ebiggers@google.com>
+Signed-off-by: Richard Weinberger <richard@nod.at>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/ubifs/ioctl.c |    3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/fs/ubifs/ioctl.c
++++ b/fs/ubifs/ioctl.c
+@@ -132,7 +132,8 @@ static int setflags(struct inode *inode,
+               }
+       }
+-      ui->flags = ioctl2ubifs(flags);
++      ui->flags &= ~ioctl2ubifs(UBIFS_SUPPORTED_IOCTL_FLAGS);
++      ui->flags |= ioctl2ubifs(flags);
+       ubifs_set_inode_flags(inode);
+       inode->i_ctime = current_time(inode);
+       release = ui->dirty;
diff --git a/queue-4.19/ubifs-reject-unsupported-ioctl-flags-explicitly.patch b/queue-4.19/ubifs-reject-unsupported-ioctl-flags-explicitly.patch
new file mode 100644 (file)
index 0000000..7539a33
--- /dev/null
@@ -0,0 +1,47 @@
+From 2fe8b2d5578d7d142982e3bf62e4c0caf8b8fe02 Mon Sep 17 00:00:00 2001
+From: Hou Tao <houtao1@huawei.com>
+Date: Sat, 9 Feb 2019 16:54:20 +0800
+Subject: ubifs: Reject unsupported ioctl flags explicitly
+
+From: Hou Tao <houtao1@huawei.com>
+
+commit 2fe8b2d5578d7d142982e3bf62e4c0caf8b8fe02 upstream.
+
+Reject unsupported ioctl flags explicitly, so the following command
+on a regular ubifs file will fail:
+       chattr +d ubifs_file
+
+And xfstests generic/424 will pass.
+
+Signed-off-by: Hou Tao <houtao1@huawei.com>
+Signed-off-by: Richard Weinberger <richard@nod.at>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/ubifs/ioctl.c |    8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+--- a/fs/ubifs/ioctl.c
++++ b/fs/ubifs/ioctl.c
+@@ -28,6 +28,11 @@
+ #include <linux/mount.h>
+ #include "ubifs.h"
++/* Need to be kept consistent with checked flags in ioctl2ubifs() */
++#define UBIFS_SUPPORTED_IOCTL_FLAGS \
++      (FS_COMPR_FL | FS_SYNC_FL | FS_APPEND_FL | \
++       FS_IMMUTABLE_FL | FS_DIRSYNC_FL)
++
+ /**
+  * ubifs_set_inode_flags - set VFS inode flags.
+  * @inode: VFS inode to set flags for
+@@ -169,6 +174,9 @@ long ubifs_ioctl(struct file *file, unsi
+               if (get_user(flags, (int __user *) arg))
+                       return -EFAULT;
++              if (flags & ~UBIFS_SUPPORTED_IOCTL_FLAGS)
++                      return -EOPNOTSUPP;
++
+               if (!S_ISDIR(inode->i_mode))
+                       flags &= ~FS_DIRSYNC_FL;