]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
Fixes for 6.5
authorSasha Levin <sashal@kernel.org>
Sun, 10 Sep 2023 14:39:21 +0000 (10:39 -0400)
committerSasha Levin <sashal@kernel.org>
Sun, 10 Sep 2023 14:39:21 +0000 (10:39 -0400)
Signed-off-by: Sasha Levin <sashal@kernel.org>
queue-6.5/bluetooth-hci-introduce-hci_quirk_broken_le_coded.patch [new file with mode: 0644]
queue-6.5/bluetooth-msft-extended-monitor-tracking-by-address-.patch [new file with mode: 0644]
queue-6.5/memfd-do-not-eacces-old-memfd_create-users-with-vm.m.patch [new file with mode: 0644]
queue-6.5/memfd-improve-userspace-warnings-for-missing-exec-re.patch [new file with mode: 0644]
queue-6.5/memfd-replace-ratcheting-feature-from-vm.memfd_noexe.patch [new file with mode: 0644]
queue-6.5/mm-memfd-sysctl-fix-memfd_noexec_scope_noexec_enforc.patch [new file with mode: 0644]
queue-6.5/selftests-memfd-sysctl-fix-memfd_noexec_scope_noexec.patch [new file with mode: 0644]
queue-6.5/serial-sc16is7xx-fix-regression-with-gpio-configurat.patch [new file with mode: 0644]
queue-6.5/serial-sc16is7xx-remove-obsolete-out_thread-label.patch [new file with mode: 0644]
queue-6.5/series

diff --git a/queue-6.5/bluetooth-hci-introduce-hci_quirk_broken_le_coded.patch b/queue-6.5/bluetooth-hci-introduce-hci_quirk_broken_le_coded.patch
new file mode 100644 (file)
index 0000000..f28e904
--- /dev/null
@@ -0,0 +1,106 @@
+From e0e4a169311075ab305352546fb07bded269bdf2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 22 Aug 2023 12:02:03 -0700
+Subject: Bluetooth: HCI: Introduce HCI_QUIRK_BROKEN_LE_CODED
+
+From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+
+[ Upstream commit 253f3399f4c09ce6f4e67350f839be0361b4d5ff ]
+
+This introduces HCI_QUIRK_BROKEN_LE_CODED which is used to indicate
+that LE Coded PHY shall not be used, it is then set for some Intel
+models that claim to support it but when used causes many problems.
+
+Cc: stable@vger.kernel.org # 6.4.y+
+Link: https://github.com/bluez/bluez/issues/577
+Link: https://github.com/bluez/bluez/issues/582
+Link: https://lore.kernel.org/linux-bluetooth/CABBYNZKco-v7wkjHHexxQbgwwSz-S=GZ=dZKbRE1qxT1h4fFbQ@mail.gmail.com/T/#
+Fixes: 288c90224eec ("Bluetooth: Enable all supported LE PHY by default")
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/bluetooth/btintel.c      |  6 ++++++
+ include/net/bluetooth/hci.h      | 10 ++++++++++
+ include/net/bluetooth/hci_core.h |  4 +++-
+ net/bluetooth/hci_sync.c         |  5 ++++-
+ 4 files changed, 23 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c
+index d9349ba48281e..7ba60151a16a6 100644
+--- a/drivers/bluetooth/btintel.c
++++ b/drivers/bluetooth/btintel.c
+@@ -2658,6 +2658,9 @@ static int btintel_setup_combined(struct hci_dev *hdev)
+                       set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED,
+                               &hdev->quirks);
++                      /* These variants don't seem to support LE Coded PHY */
++                      set_bit(HCI_QUIRK_BROKEN_LE_CODED, &hdev->quirks);
++
+                       /* Setup MSFT Extension support */
+                       btintel_set_msft_opcode(hdev, ver.hw_variant);
+@@ -2729,6 +2732,9 @@ static int btintel_setup_combined(struct hci_dev *hdev)
+                */
+               set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks);
++              /* These variants don't seem to support LE Coded PHY */
++              set_bit(HCI_QUIRK_BROKEN_LE_CODED, &hdev->quirks);
++
+               /* Set Valid LE States quirk */
+               set_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks);
+diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
+index 9ae6f60c96bf2..3ff822ebb3a47 100644
+--- a/include/net/bluetooth/hci.h
++++ b/include/net/bluetooth/hci.h
+@@ -319,6 +319,16 @@ enum {
+        * This quirk must be set before hci_register_dev is called.
+        */
+       HCI_QUIRK_USE_MSFT_EXT_ADDRESS_FILTER,
++
++      /*
++       * When this quirk is set, LE Coded PHY shall not be used. This is
++       * required for some Intel controllers which erroneously claim to
++       * support it but it causes problems with extended scanning.
++       *
++       * This quirk can be set before hci_register_dev is called or
++       * during the hdev->setup vendor callback.
++       */
++      HCI_QUIRK_BROKEN_LE_CODED,
+ };
+ /* HCI device flags */
+diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
+index 2a9cdbdb8a81e..c0a87558aea71 100644
+--- a/include/net/bluetooth/hci_core.h
++++ b/include/net/bluetooth/hci_core.h
+@@ -1770,7 +1770,9 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
+ #define scan_2m(dev) (((dev)->le_tx_def_phys & HCI_LE_SET_PHY_2M) || \
+                     ((dev)->le_rx_def_phys & HCI_LE_SET_PHY_2M))
+-#define le_coded_capable(dev) (((dev)->le_features[1] & HCI_LE_PHY_CODED))
++#define le_coded_capable(dev) (((dev)->le_features[1] & HCI_LE_PHY_CODED) && \
++                             !test_bit(HCI_QUIRK_BROKEN_LE_CODED, \
++                                       &(dev)->quirks))
+ #define scan_coded(dev) (((dev)->le_tx_def_phys & HCI_LE_SET_PHY_CODED) || \
+                        ((dev)->le_rx_def_phys & HCI_LE_SET_PHY_CODED))
+diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
+index bc84b4617e824..402b8522c2228 100644
+--- a/net/bluetooth/hci_sync.c
++++ b/net/bluetooth/hci_sync.c
+@@ -4684,7 +4684,10 @@ static const struct {
+                        "advertised, but not supported."),
+       HCI_QUIRK_BROKEN(SET_RPA_TIMEOUT,
+                        "HCI LE Set Random Private Address Timeout command is "
+-                       "advertised, but not supported.")
++                       "advertised, but not supported."),
++      HCI_QUIRK_BROKEN(LE_CODED,
++                       "HCI LE Coded PHY feature bit is set, "
++                       "but its usage is not supported.")
+ };
+ /* This function handles hdev setup stage:
+-- 
+2.40.1
+
diff --git a/queue-6.5/bluetooth-msft-extended-monitor-tracking-by-address-.patch b/queue-6.5/bluetooth-msft-extended-monitor-tracking-by-address-.patch
new file mode 100644 (file)
index 0000000..c2d9387
--- /dev/null
@@ -0,0 +1,669 @@
+From 929cbac299030c0d174e676d1e5de403e313d920 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 21 Jun 2023 18:00:31 +0800
+Subject: Bluetooth: msft: Extended monitor tracking by address filter
+
+From: Hilda Wu <hildawu@realtek.com>
+
+[ Upstream commit 9e14606d8f38ea52a38c27692a9c1513c987a5da ]
+
+Since limited tracking device per condition, this feature is to support
+tracking multiple devices concurrently.
+When a pattern monitor detects the device, this feature issues an address
+monitor for tracking that device. Let pattern monitor can keep monitor
+new devices.
+This feature adds an address filter when receiving a LE monitor device
+event which monitor handle is for a pattern, and the controller started
+monitoring the device. And this feature also has cancelled the monitor
+advertisement from address filters when receiving a LE monitor device
+event when the controller stopped monitoring the device specified by an
+address and monitor handle.
+
+Below is an example to know the feature adds the address filter.
+
+//Add MSFT pattern monitor
+< HCI Command: Vendor (0x3f|0x00f0) plen 14          #142 [hci0] 55.552420
+        03 b8 a4 03 ff 01 01 06 09 05 5f 52 45 46        .........._REF
+> HCI Event: Command Complete (0x0e) plen 6          #143 [hci0] 55.653960
+      Vendor (0x3f|0x00f0) ncmd 2
+        Status: Success (0x00)
+        03 00
+
+//Got event from the pattern monitor
+> HCI Event: Vendor (0xff) plen 18                   #148 [hci0] 58.384953
+        23 79 54 33 77 88 97 68 02 00 fb c1 29 eb 27 b8  #yT3w..h....).'.
+        00 01                                            ..
+
+//Add MSFT address monitor (Sample address: B8:27:EB:29:C1:FB)
+< HCI Command: Vendor (0x3f|0x00f0) plen 13          #149 [hci0] 58.385067
+        03 b8 a4 03 ff 04 00 fb c1 29 eb 27 b8           .........).'.
+
+//Report to userspace about found device (ADV Monitor Device Found)
+@ MGMT Event: Unknown (0x002f) plen 38           {0x0003} [hci0] 58.680042
+        01 00 fb c1 29 eb 27 b8 01 ce 00 00 00 00 16 00  ....).'.........
+        0a 09 4b 45 59 42 44 5f 52 45 46 02 01 06 03 19  ..KEYBD_REF.....
+        c1 03 03 03 12 18                                ......
+
+//Got event from address monitor
+> HCI Event: Vendor (0xff) plen 18                   #152 [hci0] 58.672956
+        23 79 54 33 77 88 97 68 02 00 fb c1 29 eb 27 b8  #yT3w..h....).'.
+        01 01
+
+Signed-off-by: Alex Lu <alex_lu@realsil.com.cn>
+Signed-off-by: Hilda Wu <hildawu@realtek.com>
+Reviewed-by: Simon Horman <simon.horman@corigine.com>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Stable-dep-of: 253f3399f4c0 ("Bluetooth: HCI: Introduce HCI_QUIRK_BROKEN_LE_CODED")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/bluetooth/btrtl.c   |   4 +
+ include/net/bluetooth/hci.h |  10 +
+ net/bluetooth/msft.c        | 412 ++++++++++++++++++++++++++++++++++--
+ 3 files changed, 411 insertions(+), 15 deletions(-)
+
+diff --git a/drivers/bluetooth/btrtl.c b/drivers/bluetooth/btrtl.c
+index 8824686bb09dc..c06a04080cd75 100644
+--- a/drivers/bluetooth/btrtl.c
++++ b/drivers/bluetooth/btrtl.c
+@@ -1199,6 +1199,10 @@ void btrtl_set_quirks(struct hci_dev *hdev, struct btrtl_device_info *btrtl_dev)
+               if (btrtl_dev->project_id == CHIP_ID_8852C)
+                       btrealtek_set_flag(hdev, REALTEK_ALT6_CONTINUOUS_TX_CHIP);
++              if (btrtl_dev->project_id == CHIP_ID_8852A ||
++                  btrtl_dev->project_id == CHIP_ID_8852C)
++                      set_bit(HCI_QUIRK_USE_MSFT_EXT_ADDRESS_FILTER, &hdev->quirks);
++
+               hci_set_aosp_capable(hdev);
+               break;
+       default:
+diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
+index 872dcb91a540e..9ae6f60c96bf2 100644
+--- a/include/net/bluetooth/hci.h
++++ b/include/net/bluetooth/hci.h
+@@ -309,6 +309,16 @@ enum {
+        * to support it.
+        */
+       HCI_QUIRK_BROKEN_SET_RPA_TIMEOUT,
++
++      /* When this quirk is set, MSFT extension monitor tracking by
++       * address filter is supported. Since tracking quantity of each
++       * pattern is limited, this feature supports tracking multiple
++       * devices concurrently if controller supports multiple
++       * address filters.
++       *
++       * This quirk must be set before hci_register_dev is called.
++       */
++      HCI_QUIRK_USE_MSFT_EXT_ADDRESS_FILTER,
+ };
+ /* HCI device flags */
+diff --git a/net/bluetooth/msft.c b/net/bluetooth/msft.c
+index bf5cee48916c7..b80a2162a5c33 100644
+--- a/net/bluetooth/msft.c
++++ b/net/bluetooth/msft.c
+@@ -91,6 +91,33 @@ struct msft_ev_le_monitor_device {
+ struct msft_monitor_advertisement_handle_data {
+       __u8  msft_handle;
+       __u16 mgmt_handle;
++      __s8 rssi_high;
++      __s8 rssi_low;
++      __u8 rssi_low_interval;
++      __u8 rssi_sampling_period;
++      __u8 cond_type;
++      struct list_head list;
++};
++
++enum monitor_addr_filter_state {
++      AF_STATE_IDLE,
++      AF_STATE_ADDING,
++      AF_STATE_ADDED,
++      AF_STATE_REMOVING,
++};
++
++#define MSFT_MONITOR_ADVERTISEMENT_TYPE_ADDR  0x04
++struct msft_monitor_addr_filter_data {
++      __u8     msft_handle;
++      __u8     pattern_handle; /* address filters pertain to */
++      __u16    mgmt_handle;
++      int      state;
++      __s8     rssi_high;
++      __s8     rssi_low;
++      __u8     rssi_low_interval;
++      __u8     rssi_sampling_period;
++      __u8     addr_type;
++      bdaddr_t bdaddr;
+       struct list_head list;
+ };
+@@ -99,9 +126,12 @@ struct msft_data {
+       __u8  evt_prefix_len;
+       __u8  *evt_prefix;
+       struct list_head handle_map;
++      struct list_head address_filters;
+       __u8 resuming;
+       __u8 suspending;
+       __u8 filter_enabled;
++      /* To synchronize add/remove address filter and monitor device event.*/
++      struct mutex filter_lock;
+ };
+ bool msft_monitor_supported(struct hci_dev *hdev)
+@@ -180,6 +210,24 @@ static struct msft_monitor_advertisement_handle_data *msft_find_handle_data
+       return NULL;
+ }
++/* This function requires the caller holds msft->filter_lock */
++static struct msft_monitor_addr_filter_data *msft_find_address_data
++                      (struct hci_dev *hdev, u8 addr_type, bdaddr_t *addr,
++                       u8 pattern_handle)
++{
++      struct msft_monitor_addr_filter_data *entry;
++      struct msft_data *msft = hdev->msft_data;
++
++      list_for_each_entry(entry, &msft->address_filters, list) {
++              if (entry->pattern_handle == pattern_handle &&
++                  addr_type == entry->addr_type &&
++                  !bacmp(addr, &entry->bdaddr))
++                      return entry;
++      }
++
++      return NULL;
++}
++
+ /* This function requires the caller holds hdev->lock */
+ static int msft_monitor_device_del(struct hci_dev *hdev, __u16 mgmt_handle,
+                                  bdaddr_t *bdaddr, __u8 addr_type,
+@@ -240,6 +288,7 @@ static int msft_le_monitor_advertisement_cb(struct hci_dev *hdev, u16 opcode,
+       handle_data->mgmt_handle = monitor->handle;
+       handle_data->msft_handle = rp->handle;
++      handle_data->cond_type   = MSFT_MONITOR_ADVERTISEMENT_TYPE_PATTERN;
+       INIT_LIST_HEAD(&handle_data->list);
+       list_add(&handle_data->list, &msft->handle_map);
+@@ -254,6 +303,70 @@ static int msft_le_monitor_advertisement_cb(struct hci_dev *hdev, u16 opcode,
+       return status;
+ }
++/* This function requires the caller holds hci_req_sync_lock */
++static void msft_remove_addr_filters_sync(struct hci_dev *hdev, u8 handle)
++{
++      struct msft_monitor_addr_filter_data *address_filter, *n;
++      struct msft_cp_le_cancel_monitor_advertisement cp;
++      struct msft_data *msft = hdev->msft_data;
++      struct list_head head;
++      struct sk_buff *skb;
++
++      INIT_LIST_HEAD(&head);
++
++      /* Cancel all corresponding address monitors */
++      mutex_lock(&msft->filter_lock);
++
++      list_for_each_entry_safe(address_filter, n, &msft->address_filters,
++                               list) {
++              if (address_filter->pattern_handle != handle)
++                      continue;
++
++              list_del(&address_filter->list);
++
++              /* Keep the address filter and let
++               * msft_add_address_filter_sync() remove and free the address
++               * filter.
++               */
++              if (address_filter->state == AF_STATE_ADDING) {
++                      address_filter->state = AF_STATE_REMOVING;
++                      continue;
++              }
++
++              /* Keep the address filter and let
++               * msft_cancel_address_filter_sync() remove and free the address
++               * filter
++               */
++              if (address_filter->state == AF_STATE_REMOVING)
++                      continue;
++
++              list_add_tail(&address_filter->list, &head);
++      }
++
++      mutex_unlock(&msft->filter_lock);
++
++      list_for_each_entry_safe(address_filter, n, &head, list) {
++              list_del(&address_filter->list);
++
++              cp.sub_opcode = MSFT_OP_LE_CANCEL_MONITOR_ADVERTISEMENT;
++              cp.handle = address_filter->msft_handle;
++
++              skb = __hci_cmd_sync(hdev, hdev->msft_opcode, sizeof(cp), &cp,
++                                   HCI_CMD_TIMEOUT);
++              if (IS_ERR_OR_NULL(skb)) {
++                      kfree(address_filter);
++                      continue;
++              }
++
++              kfree_skb(skb);
++
++              bt_dev_dbg(hdev, "MSFT: Canceled device %pMR address filter",
++                         &address_filter->bdaddr);
++
++              kfree(address_filter);
++      }
++}
++
+ static int msft_le_cancel_monitor_advertisement_cb(struct hci_dev *hdev,
+                                                  u16 opcode,
+                                                  struct adv_monitor *monitor,
+@@ -263,6 +376,7 @@ static int msft_le_cancel_monitor_advertisement_cb(struct hci_dev *hdev,
+       struct msft_monitor_advertisement_handle_data *handle_data;
+       struct msft_data *msft = hdev->msft_data;
+       int status = 0;
++      u8 msft_handle;
+       rp = (struct msft_rp_le_cancel_monitor_advertisement *)skb->data;
+       if (skb->len < sizeof(*rp)) {
+@@ -293,11 +407,17 @@ static int msft_le_cancel_monitor_advertisement_cb(struct hci_dev *hdev,
+                                               NULL, 0, false);
+               }
++              msft_handle = handle_data->msft_handle;
++
+               list_del(&handle_data->list);
+               kfree(handle_data);
+-      }
+-      hci_dev_unlock(hdev);
++              hci_dev_unlock(hdev);
++
++              msft_remove_addr_filters_sync(hdev, msft_handle);
++      } else {
++              hci_dev_unlock(hdev);
++      }
+ done:
+       return status;
+@@ -394,12 +514,14 @@ static int msft_add_monitor_sync(struct hci_dev *hdev,
+ {
+       struct msft_cp_le_monitor_advertisement *cp;
+       struct msft_le_monitor_advertisement_pattern_data *pattern_data;
++      struct msft_monitor_advertisement_handle_data *handle_data;
+       struct msft_le_monitor_advertisement_pattern *pattern;
+       struct adv_pattern *entry;
+       size_t total_size = sizeof(*cp) + sizeof(*pattern_data);
+       ptrdiff_t offset = 0;
+       u8 pattern_count = 0;
+       struct sk_buff *skb;
++      int err;
+       if (!msft_monitor_pattern_valid(monitor))
+               return -EINVAL;
+@@ -436,16 +558,31 @@ static int msft_add_monitor_sync(struct hci_dev *hdev,
+       skb = __hci_cmd_sync(hdev, hdev->msft_opcode, total_size, cp,
+                            HCI_CMD_TIMEOUT);
+-      kfree(cp);
+       if (IS_ERR_OR_NULL(skb)) {
+-              if (!skb)
+-                      return -EIO;
+-              return PTR_ERR(skb);
++              err = PTR_ERR(skb);
++              goto out_free;
+       }
+-      return msft_le_monitor_advertisement_cb(hdev, hdev->msft_opcode,
+-                                              monitor, skb);
++      err = msft_le_monitor_advertisement_cb(hdev, hdev->msft_opcode,
++                                             monitor, skb);
++      if (err)
++              goto out_free;
++
++      handle_data = msft_find_handle_data(hdev, monitor->handle, true);
++      if (!handle_data) {
++              err = -ENODATA;
++              goto out_free;
++      }
++
++      handle_data->rssi_high  = cp->rssi_high;
++      handle_data->rssi_low   = cp->rssi_low;
++      handle_data->rssi_low_interval    = cp->rssi_low_interval;
++      handle_data->rssi_sampling_period = cp->rssi_sampling_period;
++
++out_free:
++      kfree(cp);
++      return err;
+ }
+ /* This function requires the caller holds hci_req_sync_lock */
+@@ -538,6 +675,7 @@ void msft_do_close(struct hci_dev *hdev)
+ {
+       struct msft_data *msft = hdev->msft_data;
+       struct msft_monitor_advertisement_handle_data *handle_data, *tmp;
++      struct msft_monitor_addr_filter_data *address_filter, *n;
+       struct adv_monitor *monitor;
+       if (!msft)
+@@ -559,6 +697,14 @@ void msft_do_close(struct hci_dev *hdev)
+               kfree(handle_data);
+       }
++      mutex_lock(&msft->filter_lock);
++      list_for_each_entry_safe(address_filter, n, &msft->address_filters,
++                               list) {
++              list_del(&address_filter->list);
++              kfree(address_filter);
++      }
++      mutex_unlock(&msft->filter_lock);
++
+       hci_dev_lock(hdev);
+       /* Clear any devices that are being monitored and notify device lost */
+@@ -568,6 +714,49 @@ void msft_do_close(struct hci_dev *hdev)
+       hci_dev_unlock(hdev);
+ }
++static int msft_cancel_address_filter_sync(struct hci_dev *hdev, void *data)
++{
++      struct msft_monitor_addr_filter_data *address_filter = data;
++      struct msft_cp_le_cancel_monitor_advertisement cp;
++      struct msft_data *msft = hdev->msft_data;
++      struct sk_buff *skb;
++      int err = 0;
++
++      if (!msft) {
++              bt_dev_err(hdev, "MSFT: msft data is freed");
++              return -EINVAL;
++      }
++
++      /* The address filter has been removed by hci dev close */
++      if (!test_bit(HCI_UP, &hdev->flags))
++              return 0;
++
++      mutex_lock(&msft->filter_lock);
++      list_del(&address_filter->list);
++      mutex_unlock(&msft->filter_lock);
++
++      cp.sub_opcode = MSFT_OP_LE_CANCEL_MONITOR_ADVERTISEMENT;
++      cp.handle = address_filter->msft_handle;
++
++      skb = __hci_cmd_sync(hdev, hdev->msft_opcode, sizeof(cp), &cp,
++                           HCI_CMD_TIMEOUT);
++      if (IS_ERR_OR_NULL(skb)) {
++              bt_dev_err(hdev, "MSFT: Failed to cancel address (%pMR) filter",
++                         &address_filter->bdaddr);
++              err = EIO;
++              goto done;
++      }
++      kfree_skb(skb);
++
++      bt_dev_dbg(hdev, "MSFT: Canceled device %pMR address filter",
++                 &address_filter->bdaddr);
++
++done:
++      kfree(address_filter);
++
++      return err;
++}
++
+ void msft_register(struct hci_dev *hdev)
+ {
+       struct msft_data *msft = NULL;
+@@ -581,7 +770,9 @@ void msft_register(struct hci_dev *hdev)
+       }
+       INIT_LIST_HEAD(&msft->handle_map);
++      INIT_LIST_HEAD(&msft->address_filters);
+       hdev->msft_data = msft;
++      mutex_init(&msft->filter_lock);
+ }
+ void msft_unregister(struct hci_dev *hdev)
+@@ -596,6 +787,7 @@ void msft_unregister(struct hci_dev *hdev)
+       hdev->msft_data = NULL;
+       kfree(msft->evt_prefix);
++      mutex_destroy(&msft->filter_lock);
+       kfree(msft);
+ }
+@@ -645,11 +837,149 @@ static void *msft_skb_pull(struct hci_dev *hdev, struct sk_buff *skb,
+       return data;
+ }
++static int msft_add_address_filter_sync(struct hci_dev *hdev, void *data)
++{
++      struct msft_monitor_addr_filter_data *address_filter = data;
++      struct msft_rp_le_monitor_advertisement *rp;
++      struct msft_cp_le_monitor_advertisement *cp;
++      struct msft_data *msft = hdev->msft_data;
++      struct sk_buff *skb = NULL;
++      bool remove = false;
++      size_t size;
++
++      if (!msft) {
++              bt_dev_err(hdev, "MSFT: msft data is freed");
++              return -EINVAL;
++      }
++
++      /* The address filter has been removed by hci dev close */
++      if (!test_bit(HCI_UP, &hdev->flags))
++              return -ENODEV;
++
++      /* We are safe to use the address filter from now on.
++       * msft_monitor_device_evt() wouldn't delete this filter because it's
++       * not been added by now.
++       * And all other functions that requiring hci_req_sync_lock wouldn't
++       * touch this filter before this func completes because it's protected
++       * by hci_req_sync_lock.
++       */
++
++      if (address_filter->state == AF_STATE_REMOVING) {
++              mutex_lock(&msft->filter_lock);
++              list_del(&address_filter->list);
++              mutex_unlock(&msft->filter_lock);
++              kfree(address_filter);
++              return 0;
++      }
++
++      size = sizeof(*cp) +
++             sizeof(address_filter->addr_type) +
++             sizeof(address_filter->bdaddr);
++      cp = kzalloc(size, GFP_KERNEL);
++      if (!cp) {
++              bt_dev_err(hdev, "MSFT: Alloc cmd param err");
++              remove = true;
++              goto done;
++      }
++      cp->sub_opcode           = MSFT_OP_LE_MONITOR_ADVERTISEMENT;
++      cp->rssi_high            = address_filter->rssi_high;
++      cp->rssi_low             = address_filter->rssi_low;
++      cp->rssi_low_interval    = address_filter->rssi_low_interval;
++      cp->rssi_sampling_period = address_filter->rssi_sampling_period;
++      cp->cond_type            = MSFT_MONITOR_ADVERTISEMENT_TYPE_ADDR;
++      cp->data[0]              = address_filter->addr_type;
++      memcpy(&cp->data[1], &address_filter->bdaddr,
++             sizeof(address_filter->bdaddr));
++
++      skb = __hci_cmd_sync(hdev, hdev->msft_opcode, size, cp,
++                           HCI_CMD_TIMEOUT);
++      if (IS_ERR_OR_NULL(skb)) {
++              bt_dev_err(hdev, "Failed to enable address %pMR filter",
++                         &address_filter->bdaddr);
++              skb = NULL;
++              remove = true;
++              goto done;
++      }
++
++      rp = skb_pull_data(skb, sizeof(*rp));
++      if (!rp || rp->sub_opcode != MSFT_OP_LE_MONITOR_ADVERTISEMENT ||
++          rp->status)
++              remove = true;
++
++done:
++      mutex_lock(&msft->filter_lock);
++
++      if (remove) {
++              bt_dev_warn(hdev, "MSFT: Remove address (%pMR) filter",
++                          &address_filter->bdaddr);
++              list_del(&address_filter->list);
++              kfree(address_filter);
++      } else {
++              address_filter->state = AF_STATE_ADDED;
++              address_filter->msft_handle = rp->handle;
++              bt_dev_dbg(hdev, "MSFT: Address %pMR filter enabled",
++                         &address_filter->bdaddr);
++      }
++      mutex_unlock(&msft->filter_lock);
++
++      kfree_skb(skb);
++
++      return 0;
++}
++
++/* This function requires the caller holds msft->filter_lock */
++static struct msft_monitor_addr_filter_data *msft_add_address_filter
++              (struct hci_dev *hdev, u8 addr_type, bdaddr_t *bdaddr,
++               struct msft_monitor_advertisement_handle_data *handle_data)
++{
++      struct msft_monitor_addr_filter_data *address_filter = NULL;
++      struct msft_data *msft = hdev->msft_data;
++      int err;
++
++      address_filter = kzalloc(sizeof(*address_filter), GFP_KERNEL);
++      if (!address_filter)
++              return NULL;
++
++      address_filter->state             = AF_STATE_ADDING;
++      address_filter->msft_handle       = 0xff;
++      address_filter->pattern_handle    = handle_data->msft_handle;
++      address_filter->mgmt_handle       = handle_data->mgmt_handle;
++      address_filter->rssi_high         = handle_data->rssi_high;
++      address_filter->rssi_low          = handle_data->rssi_low;
++      address_filter->rssi_low_interval = handle_data->rssi_low_interval;
++      address_filter->rssi_sampling_period = handle_data->rssi_sampling_period;
++      address_filter->addr_type            = addr_type;
++      bacpy(&address_filter->bdaddr, bdaddr);
++
++      /* With the above AF_STATE_ADDING, duplicated address filter can be
++       * avoided when receiving monitor device event (found/lost) frequently
++       * for the same device.
++       */
++      list_add_tail(&address_filter->list, &msft->address_filters);
++
++      err = hci_cmd_sync_queue(hdev, msft_add_address_filter_sync,
++                               address_filter, NULL);
++      if (err < 0) {
++              bt_dev_err(hdev, "MSFT: Add address %pMR filter err", bdaddr);
++              list_del(&address_filter->list);
++              kfree(address_filter);
++              return NULL;
++      }
++
++      bt_dev_dbg(hdev, "MSFT: Add device %pMR address filter",
++                 &address_filter->bdaddr);
++
++      return address_filter;
++}
++
+ /* This function requires the caller holds hdev->lock */
+ static void msft_monitor_device_evt(struct hci_dev *hdev, struct sk_buff *skb)
+ {
++      struct msft_monitor_addr_filter_data *n, *address_filter = NULL;
+       struct msft_ev_le_monitor_device *ev;
+       struct msft_monitor_advertisement_handle_data *handle_data;
++      struct msft_data *msft = hdev->msft_data;
++      u16 mgmt_handle = 0xffff;
+       u8 addr_type;
+       ev = msft_skb_pull(hdev, skb, MSFT_EV_LE_MONITOR_DEVICE, sizeof(*ev));
+@@ -662,9 +992,53 @@ static void msft_monitor_device_evt(struct hci_dev *hdev, struct sk_buff *skb)
+                  ev->monitor_state, &ev->bdaddr);
+       handle_data = msft_find_handle_data(hdev, ev->monitor_handle, false);
+-      if (!handle_data)
++
++      if (!test_bit(HCI_QUIRK_USE_MSFT_EXT_ADDRESS_FILTER, &hdev->quirks)) {
++              if (!handle_data)
++                      return;
++              mgmt_handle = handle_data->mgmt_handle;
++              goto report_state;
++      }
++
++      if (handle_data) {
++              /* Don't report any device found/lost event from pattern
++               * monitors. Pattern monitor always has its address filters for
++               * tracking devices.
++               */
++
++              address_filter = msft_find_address_data(hdev, ev->addr_type,
++                                                      &ev->bdaddr,
++                                                      handle_data->msft_handle);
++              if (address_filter)
++                      return;
++
++              if (ev->monitor_state && handle_data->cond_type ==
++                              MSFT_MONITOR_ADVERTISEMENT_TYPE_PATTERN)
++                      msft_add_address_filter(hdev, ev->addr_type,
++                                              &ev->bdaddr, handle_data);
++
+               return;
++      }
++      /* This device event is not from pattern monitor.
++       * Report it if there is a corresponding address_filter for it.
++       */
++      list_for_each_entry(n, &msft->address_filters, list) {
++              if (n->state == AF_STATE_ADDED &&
++                  n->msft_handle == ev->monitor_handle) {
++                      mgmt_handle = n->mgmt_handle;
++                      address_filter = n;
++                      break;
++              }
++      }
++
++      if (!address_filter) {
++              bt_dev_warn(hdev, "MSFT: Unexpected device event %pMR, %u, %u",
++                          &ev->bdaddr, ev->monitor_handle, ev->monitor_state);
++              return;
++      }
++
++report_state:
+       switch (ev->addr_type) {
+       case ADDR_LE_DEV_PUBLIC:
+               addr_type = BDADDR_LE_PUBLIC;
+@@ -681,12 +1055,18 @@ static void msft_monitor_device_evt(struct hci_dev *hdev, struct sk_buff *skb)
+               return;
+       }
+-      if (ev->monitor_state)
+-              msft_device_found(hdev, &ev->bdaddr, addr_type,
+-                                handle_data->mgmt_handle);
+-      else
+-              msft_device_lost(hdev, &ev->bdaddr, addr_type,
+-                               handle_data->mgmt_handle);
++      if (ev->monitor_state) {
++              msft_device_found(hdev, &ev->bdaddr, addr_type, mgmt_handle);
++      } else {
++              if (address_filter && address_filter->state == AF_STATE_ADDED) {
++                      address_filter->state = AF_STATE_REMOVING;
++                      hci_cmd_sync_queue(hdev,
++                                         msft_cancel_address_filter_sync,
++                                         address_filter,
++                                         NULL);
++              }
++              msft_device_lost(hdev, &ev->bdaddr, addr_type, mgmt_handle);
++      }
+ }
+ void msft_vendor_evt(struct hci_dev *hdev, void *data, struct sk_buff *skb)
+@@ -724,7 +1104,9 @@ void msft_vendor_evt(struct hci_dev *hdev, void *data, struct sk_buff *skb)
+       switch (*evt) {
+       case MSFT_EV_LE_MONITOR_DEVICE:
++              mutex_lock(&msft->filter_lock);
+               msft_monitor_device_evt(hdev, skb);
++              mutex_unlock(&msft->filter_lock);
+               break;
+       default:
+-- 
+2.40.1
+
diff --git a/queue-6.5/memfd-do-not-eacces-old-memfd_create-users-with-vm.m.patch b/queue-6.5/memfd-do-not-eacces-old-memfd_create-users-with-vm.m.patch
new file mode 100644 (file)
index 0000000..9bc45cc
--- /dev/null
@@ -0,0 +1,177 @@
+From 517ab256434dcf02b8d41c12db9ceedff3308dae Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 14 Aug 2023 18:40:58 +1000
+Subject: memfd: do not -EACCES old memfd_create() users with vm.memfd_noexec=2
+
+From: Aleksa Sarai <cyphar@cyphar.com>
+
+[ Upstream commit 202e14222fadb246dfdf182e67de1518e86a1e20 ]
+
+Given the difficulty of auditing all of userspace to figure out whether
+every memfd_create() user has switched to passing MFD_EXEC and
+MFD_NOEXEC_SEAL flags, it seems far less distruptive to make it possible
+for older programs that don't make use of executable memfds to run under
+vm.memfd_noexec=2.  Otherwise, a small dependency change can result in
+spurious errors.  For programs that don't use executable memfds, passing
+MFD_NOEXEC_SEAL is functionally a no-op and thus having the same
+
+In addition, every failure under vm.memfd_noexec=2 needs to print to the
+kernel log so that userspace can figure out where the error came from.
+The concerns about pr_warn_ratelimited() spam that caused the switch to
+pr_warn_once()[1,2] do not apply to the vm.memfd_noexec=2 case.
+
+This is a user-visible API change, but as it allows programs to do
+something that would be blocked before, and the sysctl itself was broken
+and recently released, it seems unlikely this will cause any issues.
+
+[1]: https://lore.kernel.org/Y5yS8wCnuYGLHMj4@x1n/
+[2]: https://lore.kernel.org/202212161233.85C9783FB@keescook/
+
+Link: https://lkml.kernel.org/r/20230814-memfd-vm-noexec-uapi-fixes-v2-2-7ff9e3e10ba6@cyphar.com
+Fixes: 105ff5339f49 ("mm/memfd: add MFD_NOEXEC_SEAL and MFD_EXEC")
+Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
+Cc: Dominique Martinet <asmadeus@codewreck.org>
+Cc: Christian Brauner <brauner@kernel.org>
+Cc: Daniel Verkamp <dverkamp@chromium.org>
+Cc: Jeff Xu <jeffxu@google.com>
+Cc: Kees Cook <keescook@chromium.org>
+Cc: Shuah Khan <shuah@kernel.org>
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/pid_namespace.h              | 16 +++---------
+ mm/memfd.c                                 | 30 ++++++++--------------
+ tools/testing/selftests/memfd/memfd_test.c | 22 ++++++++++++----
+ 3 files changed, 32 insertions(+), 36 deletions(-)
+
+diff --git a/include/linux/pid_namespace.h b/include/linux/pid_namespace.h
+index c758809d5bcf3..53974d79d98e8 100644
+--- a/include/linux/pid_namespace.h
++++ b/include/linux/pid_namespace.h
+@@ -17,18 +17,10 @@
+ struct fs_pin;
+ #if defined(CONFIG_SYSCTL) && defined(CONFIG_MEMFD_CREATE)
+-/*
+- * sysctl for vm.memfd_noexec
+- * 0: memfd_create() without MFD_EXEC nor MFD_NOEXEC_SEAL
+- *    acts like MFD_EXEC was set.
+- * 1: memfd_create() without MFD_EXEC nor MFD_NOEXEC_SEAL
+- *    acts like MFD_NOEXEC_SEAL was set.
+- * 2: memfd_create() without MFD_NOEXEC_SEAL will be
+- *    rejected.
+- */
+-#define MEMFD_NOEXEC_SCOPE_EXEC                       0
+-#define MEMFD_NOEXEC_SCOPE_NOEXEC_SEAL                1
+-#define MEMFD_NOEXEC_SCOPE_NOEXEC_ENFORCED    2
++/* modes for vm.memfd_noexec sysctl */
++#define MEMFD_NOEXEC_SCOPE_EXEC                       0 /* MFD_EXEC implied if unset */
++#define MEMFD_NOEXEC_SCOPE_NOEXEC_SEAL                1 /* MFD_NOEXEC_SEAL implied if unset */
++#define MEMFD_NOEXEC_SCOPE_NOEXEC_ENFORCED    2 /* same as 1, except MFD_EXEC rejected */
+ #endif
+ struct pid_namespace {
+diff --git a/mm/memfd.c b/mm/memfd.c
+index 0bdbd2335af75..d65485c762def 100644
+--- a/mm/memfd.c
++++ b/mm/memfd.c
+@@ -271,30 +271,22 @@ long memfd_fcntl(struct file *file, unsigned int cmd, unsigned int arg)
+ static int check_sysctl_memfd_noexec(unsigned int *flags)
+ {
+ #ifdef CONFIG_SYSCTL
+-      char comm[TASK_COMM_LEN];
+-      int sysctl = MEMFD_NOEXEC_SCOPE_EXEC;
+-      struct pid_namespace *ns;
+-
+-      ns = task_active_pid_ns(current);
+-      if (ns)
+-              sysctl = ns->memfd_noexec_scope;
++      int sysctl = task_active_pid_ns(current)->memfd_noexec_scope;
+       if (!(*flags & (MFD_EXEC | MFD_NOEXEC_SEAL))) {
+-              if (sysctl == MEMFD_NOEXEC_SCOPE_NOEXEC_SEAL)
++              if (sysctl >= MEMFD_NOEXEC_SCOPE_NOEXEC_SEAL)
+                       *flags |= MFD_NOEXEC_SEAL;
+               else
+                       *flags |= MFD_EXEC;
+       }
+-      if (*flags & MFD_EXEC && sysctl >= MEMFD_NOEXEC_SCOPE_NOEXEC_ENFORCED) {
+-              pr_warn_once(
+-                      "memfd_create(): MFD_NOEXEC_SEAL is enforced, pid=%d '%s'\n",
+-                      task_pid_nr(current), get_task_comm(comm, current));
+-
++      if (!(*flags & MFD_NOEXEC_SEAL) && sysctl >= MEMFD_NOEXEC_SCOPE_NOEXEC_ENFORCED) {
++              pr_err_ratelimited(
++                      "%s[%d]: memfd_create() requires MFD_NOEXEC_SEAL with vm.memfd_noexec=%d\n",
++                      current->comm, task_pid_nr(current), sysctl);
+               return -EACCES;
+       }
+ #endif
+-
+       return 0;
+ }
+@@ -302,7 +294,6 @@ SYSCALL_DEFINE2(memfd_create,
+               const char __user *, uname,
+               unsigned int, flags)
+ {
+-      char comm[TASK_COMM_LEN];
+       unsigned int *file_seals;
+       struct file *file;
+       int fd, error;
+@@ -325,12 +316,13 @@ SYSCALL_DEFINE2(memfd_create,
+       if (!(flags & (MFD_EXEC | MFD_NOEXEC_SEAL))) {
+               pr_warn_once(
+-                      "memfd_create() without MFD_EXEC nor MFD_NOEXEC_SEAL, pid=%d '%s'\n",
+-                      task_pid_nr(current), get_task_comm(comm, current));
++                      "%s[%d]: memfd_create() called without MFD_EXEC or MFD_NOEXEC_SEAL set\n",
++                      current->comm, task_pid_nr(current));
+       }
+-      if (check_sysctl_memfd_noexec(&flags) < 0)
+-              return -EACCES;
++      error = check_sysctl_memfd_noexec(&flags);
++      if (error < 0)
++              return error;
+       /* length includes terminating zero */
+       len = strnlen_user(uname, MFD_NAME_MAX_LEN + 1);
+diff --git a/tools/testing/selftests/memfd/memfd_test.c b/tools/testing/selftests/memfd/memfd_test.c
+index 8eb49204f9eac..8b7390ad81d11 100644
+--- a/tools/testing/selftests/memfd/memfd_test.c
++++ b/tools/testing/selftests/memfd/memfd_test.c
+@@ -1145,11 +1145,23 @@ static void test_sysctl_child(void)
+       printf("%s sysctl 2\n", memfd_str);
+       sysctl_assert_write("2");
+-      mfd_fail_new("kern_memfd_sysctl_2",
+-              MFD_CLOEXEC | MFD_ALLOW_SEALING);
+-      mfd_fail_new("kern_memfd_sysctl_2_MFD_EXEC",
+-              MFD_CLOEXEC | MFD_EXEC);
+-      fd = mfd_assert_new("", 0, MFD_NOEXEC_SEAL);
++      mfd_fail_new("kern_memfd_sysctl_2_exec",
++                   MFD_EXEC | MFD_CLOEXEC | MFD_ALLOW_SEALING);
++
++      fd = mfd_assert_new("kern_memfd_sysctl_2_dfl",
++                          mfd_def_size,
++                          MFD_CLOEXEC | MFD_ALLOW_SEALING);
++      mfd_assert_mode(fd, 0666);
++      mfd_assert_has_seals(fd, F_SEAL_EXEC);
++      mfd_fail_chmod(fd, 0777);
++      close(fd);
++
++      fd = mfd_assert_new("kern_memfd_sysctl_2_noexec_seal",
++                          mfd_def_size,
++                          MFD_NOEXEC_SEAL | MFD_CLOEXEC | MFD_ALLOW_SEALING);
++      mfd_assert_mode(fd, 0666);
++      mfd_assert_has_seals(fd, F_SEAL_EXEC);
++      mfd_fail_chmod(fd, 0777);
+       close(fd);
+       sysctl_fail_write("0");
+-- 
+2.40.1
+
diff --git a/queue-6.5/memfd-improve-userspace-warnings-for-missing-exec-re.patch b/queue-6.5/memfd-improve-userspace-warnings-for-missing-exec-re.patch
new file mode 100644 (file)
index 0000000..1d5d63f
--- /dev/null
@@ -0,0 +1,66 @@
+From a6229d573525387fc64572add866a2d741cf4f09 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 14 Aug 2023 18:40:59 +1000
+Subject: memfd: improve userspace warnings for missing exec-related flags
+
+From: Aleksa Sarai <cyphar@cyphar.com>
+
+[ Upstream commit 434ed3350f57c03a9654fe0619755cc137a58935 ]
+
+In order to incentivise userspace to switch to passing MFD_EXEC and
+MFD_NOEXEC_SEAL, we need to provide a warning on each attempt to call
+memfd_create() without the new flags.  pr_warn_once() is not useful
+because on most systems the one warning is burned up during the boot
+process (on my system, systemd does this within the first second of boot)
+and thus userspace will in practice never see the warnings to push them to
+switch to the new flags.
+
+The original patchset[1] used pr_warn_ratelimited(), however there were
+concerns about the degree of spam in the kernel log[2,3].  The resulting
+inability to detect every case was flagged as an issue at the time[4].
+
+While we could come up with an alternative rate-limiting scheme such as
+only outputting the message if vm.memfd_noexec has been modified, or only
+outputting the message once for a given task, these alternatives have
+downsides that don't make sense given how low-stakes a single kernel
+warning message is.  Switching to pr_info_ratelimited() instead should be
+fine -- it's possible some monitoring tool will be unhappy with a stream
+of warning-level messages but there's already plenty of info-level message
+spam in dmesg.
+
+[1]: https://lore.kernel.org/20221215001205.51969-4-jeffxu@google.com/
+[2]: https://lore.kernel.org/202212161233.85C9783FB@keescook/
+[3]: https://lore.kernel.org/Y5yS8wCnuYGLHMj4@x1n/
+[4]: https://lore.kernel.org/f185bb42-b29c-977e-312e-3349eea15383@linuxfoundation.org/
+
+Link: https://lkml.kernel.org/r/20230814-memfd-vm-noexec-uapi-fixes-v2-3-7ff9e3e10ba6@cyphar.com
+Fixes: 105ff5339f49 ("mm/memfd: add MFD_NOEXEC_SEAL and MFD_EXEC")
+Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
+Cc: Christian Brauner <brauner@kernel.org>
+Cc: Daniel Verkamp <dverkamp@chromium.org>
+Cc: Dominique Martinet <asmadeus@codewreck.org>
+Cc: Kees Cook <keescook@chromium.org>
+Cc: Shuah Khan <shuah@kernel.org>
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ mm/memfd.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/mm/memfd.c b/mm/memfd.c
+index 2dba2cb6f0d0f..1cad1904fc26b 100644
+--- a/mm/memfd.c
++++ b/mm/memfd.c
+@@ -316,7 +316,7 @@ SYSCALL_DEFINE2(memfd_create,
+               return -EINVAL;
+       if (!(flags & (MFD_EXEC | MFD_NOEXEC_SEAL))) {
+-              pr_warn_once(
++              pr_info_ratelimited(
+                       "%s[%d]: memfd_create() called without MFD_EXEC or MFD_NOEXEC_SEAL set\n",
+                       current->comm, task_pid_nr(current));
+       }
+-- 
+2.40.1
+
diff --git a/queue-6.5/memfd-replace-ratcheting-feature-from-vm.memfd_noexe.patch b/queue-6.5/memfd-replace-ratcheting-feature-from-vm.memfd_noexe.patch
new file mode 100644 (file)
index 0000000..9f7f432
--- /dev/null
@@ -0,0 +1,283 @@
+From 22d1ba33bed48f4fe6feffac9c0e64bd47c83432 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 14 Aug 2023 18:41:00 +1000
+Subject: memfd: replace ratcheting feature from vm.memfd_noexec with hierarchy
+
+From: Aleksa Sarai <cyphar@cyphar.com>
+
+[ Upstream commit 9876cfe8ec1cb3c88de31f4d58d57b0e7e22bcc4 ]
+
+This sysctl has the very unusual behaviour of not allowing any user (even
+CAP_SYS_ADMIN) to reduce the restriction setting, meaning that if you were
+to set this sysctl to a more restrictive option in the host pidns you
+would need to reboot your machine in order to reset it.
+
+The justification given in [1] is that this is a security feature and thus
+it should not be possible to disable.  Aside from the fact that we have
+plenty of security-related sysctls that can be disabled after being
+enabled (fs.protected_symlinks for instance), the protection provided by
+the sysctl is to stop users from being able to create a binary and then
+execute it.  A user with CAP_SYS_ADMIN can trivially do this without
+memfd_create(2):
+
+  % cat mount-memfd.c
+  #include <fcntl.h>
+  #include <string.h>
+  #include <stdio.h>
+  #include <stdlib.h>
+  #include <unistd.h>
+  #include <linux/mount.h>
+
+  #define SHELLCODE "#!/bin/echo this file was executed from this totally private tmpfs:"
+
+  int main(void)
+  {
+       int fsfd = fsopen("tmpfs", FSOPEN_CLOEXEC);
+       assert(fsfd >= 0);
+       assert(!fsconfig(fsfd, FSCONFIG_CMD_CREATE, NULL, NULL, 2));
+
+       int dfd = fsmount(fsfd, FSMOUNT_CLOEXEC, 0);
+       assert(dfd >= 0);
+
+       int execfd = openat(dfd, "exe", O_CREAT | O_RDWR | O_CLOEXEC, 0782);
+       assert(execfd >= 0);
+       assert(write(execfd, SHELLCODE, strlen(SHELLCODE)) == strlen(SHELLCODE));
+       assert(!close(execfd));
+
+       char *execpath = NULL;
+       char *argv[] = { "bad-exe", NULL }, *envp[] = { NULL };
+       execfd = openat(dfd, "exe", O_PATH | O_CLOEXEC);
+       assert(execfd >= 0);
+       assert(asprintf(&execpath, "/proc/self/fd/%d", execfd) > 0);
+       assert(!execve(execpath, argv, envp));
+  }
+  % ./mount-memfd
+  this file was executed from this totally private tmpfs: /proc/self/fd/5
+  %
+
+Given that it is possible for CAP_SYS_ADMIN users to create executable
+binaries without memfd_create(2) and without touching the host filesystem
+(not to mention the many other things a CAP_SYS_ADMIN process would be
+able to do that would be equivalent or worse), it seems strange to cause a
+fair amount of headache to admins when there doesn't appear to be an
+actual security benefit to blocking this.  There appear to be concerns
+about confused-deputy-esque attacks[2] but a confused deputy that can
+write to arbitrary sysctls is a bigger security issue than executable
+memfds.
+
+/* New API */
+
+The primary requirement from the original author appears to be more based
+on the need to be able to restrict an entire system in a hierarchical
+manner[3], such that child namespaces cannot re-enable executable memfds.
+
+So, implement that behaviour explicitly -- the vm.memfd_noexec scope is
+evaluated up the pidns tree to &init_pid_ns and you have the most
+restrictive value applied to you.  The new lower limit you can set
+vm.memfd_noexec is whatever limit applies to your parent.
+
+Note that a pidns will inherit a copy of the parent pidns's effective
+vm.memfd_noexec setting at unshare() time.  This matches the existing
+behaviour, and it also ensures that a pidns will never have its
+vm.memfd_noexec setting *lowered* behind its back (but it will be raised
+if the parent raises theirs).
+
+/* Backwards Compatibility */
+
+As the previous version of the sysctl didn't allow you to lower the
+setting at all, there are no backwards compatibility issues with this
+aspect of the change.
+
+However it should be noted that now that the setting is completely
+hierarchical.  Previously, a cloned pidns would just copy the current
+pidns setting, meaning that if the parent's vm.memfd_noexec was changed it
+wouldn't propoagate to existing pid namespaces.  Now, the restriction
+applies recursively.  This is a uAPI change, however:
+
+ * The sysctl is very new, having been merged in 6.3.
+ * Several aspects of the sysctl were broken up until this patchset and
+   the other patchset by Jeff Xu last month.
+
+And thus it seems incredibly unlikely that any real users would run into
+this issue. In the worst case, if this causes userspace isues we could
+make it so that modifying the setting follows the hierarchical rules but
+the restriction checking uses the cached copy.
+
+[1]: https://lore.kernel.org/CABi2SkWnAgHK1i6iqSqPMYuNEhtHBkO8jUuCvmG3RmUB5TKHJw@mail.gmail.com/
+[2]: https://lore.kernel.org/CALmYWFs_dNCzw_pW1yRAo4bGCPEtykroEQaowNULp7svwMLjOg@mail.gmail.com/
+[3]: https://lore.kernel.org/CALmYWFuahdUF7cT4cm7_TGLqPanuHXJ-hVSfZt7vpTnc18DPrw@mail.gmail.com/
+
+Link: https://lkml.kernel.org/r/20230814-memfd-vm-noexec-uapi-fixes-v2-4-7ff9e3e10ba6@cyphar.com
+Fixes: 105ff5339f49 ("mm/memfd: add MFD_NOEXEC_SEAL and MFD_EXEC")
+Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
+Cc: Dominique Martinet <asmadeus@codewreck.org>
+Cc: Christian Brauner <brauner@kernel.org>
+Cc: Daniel Verkamp <dverkamp@chromium.org>
+Cc: Jeff Xu <jeffxu@google.com>
+Cc: Kees Cook <keescook@chromium.org>
+Cc: Shuah Khan <shuah@kernel.org>
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/pid_namespace.h | 23 ++++++++++++++++++++++-
+ kernel/pid.c                  |  3 +++
+ kernel/pid_namespace.c        |  6 +++---
+ kernel/pid_sysctl.h           | 28 ++++++++++++----------------
+ mm/memfd.c                    |  3 ++-
+ 5 files changed, 42 insertions(+), 21 deletions(-)
+
+diff --git a/include/linux/pid_namespace.h b/include/linux/pid_namespace.h
+index 53974d79d98e8..f9f9931e02d6a 100644
+--- a/include/linux/pid_namespace.h
++++ b/include/linux/pid_namespace.h
+@@ -39,7 +39,6 @@ struct pid_namespace {
+       int reboot;     /* group exit code if this pidns was rebooted */
+       struct ns_common ns;
+ #if defined(CONFIG_SYSCTL) && defined(CONFIG_MEMFD_CREATE)
+-      /* sysctl for vm.memfd_noexec */
+       int memfd_noexec_scope;
+ #endif
+ } __randomize_layout;
+@@ -56,6 +55,23 @@ static inline struct pid_namespace *get_pid_ns(struct pid_namespace *ns)
+       return ns;
+ }
++#if defined(CONFIG_SYSCTL) && defined(CONFIG_MEMFD_CREATE)
++static inline int pidns_memfd_noexec_scope(struct pid_namespace *ns)
++{
++      int scope = MEMFD_NOEXEC_SCOPE_EXEC;
++
++      for (; ns; ns = ns->parent)
++              scope = max(scope, READ_ONCE(ns->memfd_noexec_scope));
++
++      return scope;
++}
++#else
++static inline int pidns_memfd_noexec_scope(struct pid_namespace *ns)
++{
++      return 0;
++}
++#endif
++
+ extern struct pid_namespace *copy_pid_ns(unsigned long flags,
+       struct user_namespace *user_ns, struct pid_namespace *ns);
+ extern void zap_pid_ns_processes(struct pid_namespace *pid_ns);
+@@ -70,6 +86,11 @@ static inline struct pid_namespace *get_pid_ns(struct pid_namespace *ns)
+       return ns;
+ }
++static inline int pidns_memfd_noexec_scope(struct pid_namespace *ns)
++{
++      return 0;
++}
++
+ static inline struct pid_namespace *copy_pid_ns(unsigned long flags,
+       struct user_namespace *user_ns, struct pid_namespace *ns)
+ {
+diff --git a/kernel/pid.c b/kernel/pid.c
+index 6a1d23a11026c..fee14a4486a31 100644
+--- a/kernel/pid.c
++++ b/kernel/pid.c
+@@ -83,6 +83,9 @@ struct pid_namespace init_pid_ns = {
+ #ifdef CONFIG_PID_NS
+       .ns.ops = &pidns_operations,
+ #endif
++#if defined(CONFIG_SYSCTL) && defined(CONFIG_MEMFD_CREATE)
++      .memfd_noexec_scope = MEMFD_NOEXEC_SCOPE_EXEC,
++#endif
+ };
+ EXPORT_SYMBOL_GPL(init_pid_ns);
+diff --git a/kernel/pid_namespace.c b/kernel/pid_namespace.c
+index 0bf44afe04dd1..619972c78774f 100644
+--- a/kernel/pid_namespace.c
++++ b/kernel/pid_namespace.c
+@@ -110,9 +110,9 @@ static struct pid_namespace *create_pid_namespace(struct user_namespace *user_ns
+       ns->user_ns = get_user_ns(user_ns);
+       ns->ucounts = ucounts;
+       ns->pid_allocated = PIDNS_ADDING;
+-
+-      initialize_memfd_noexec_scope(ns);
+-
++#if defined(CONFIG_SYSCTL) && defined(CONFIG_MEMFD_CREATE)
++      ns->memfd_noexec_scope = pidns_memfd_noexec_scope(parent_pid_ns);
++#endif
+       return ns;
+ out_free_idr:
+diff --git a/kernel/pid_sysctl.h b/kernel/pid_sysctl.h
+index b26e027fc9cd4..2ee41a3a1dfde 100644
+--- a/kernel/pid_sysctl.h
++++ b/kernel/pid_sysctl.h
+@@ -5,33 +5,30 @@
+ #include <linux/pid_namespace.h>
+ #if defined(CONFIG_SYSCTL) && defined(CONFIG_MEMFD_CREATE)
+-static inline void initialize_memfd_noexec_scope(struct pid_namespace *ns)
+-{
+-      ns->memfd_noexec_scope =
+-              task_active_pid_ns(current)->memfd_noexec_scope;
+-}
+-
+ static int pid_mfd_noexec_dointvec_minmax(struct ctl_table *table,
+       int write, void *buf, size_t *lenp, loff_t *ppos)
+ {
+       struct pid_namespace *ns = task_active_pid_ns(current);
+       struct ctl_table table_copy;
++      int err, scope, parent_scope;
+       if (write && !ns_capable(ns->user_ns, CAP_SYS_ADMIN))
+               return -EPERM;
+       table_copy = *table;
+-      if (ns != &init_pid_ns)
+-              table_copy.data = &ns->memfd_noexec_scope;
+-      /*
+-       * set minimum to current value, the effect is only bigger
+-       * value is accepted.
+-       */
+-      if (*(int *)table_copy.data > *(int *)table_copy.extra1)
+-              table_copy.extra1 = table_copy.data;
++      /* You cannot set a lower enforcement value than your parent. */
++      parent_scope = pidns_memfd_noexec_scope(ns->parent);
++      /* Equivalent to pidns_memfd_noexec_scope(ns). */
++      scope = max(READ_ONCE(ns->memfd_noexec_scope), parent_scope);
++
++      table_copy.data = &scope;
++      table_copy.extra1 = &parent_scope;
+-      return proc_dointvec_minmax(&table_copy, write, buf, lenp, ppos);
++      err = proc_dointvec_minmax(&table_copy, write, buf, lenp, ppos);
++      if (!err && write)
++              WRITE_ONCE(ns->memfd_noexec_scope, scope);
++      return err;
+ }
+ static struct ctl_table pid_ns_ctl_table_vm[] = {
+@@ -51,7 +48,6 @@ static inline void register_pid_ns_sysctl_table_vm(void)
+       register_sysctl("vm", pid_ns_ctl_table_vm);
+ }
+ #else
+-static inline void initialize_memfd_noexec_scope(struct pid_namespace *ns) {}
+ static inline void register_pid_ns_sysctl_table_vm(void) {}
+ #endif
+diff --git a/mm/memfd.c b/mm/memfd.c
+index d65485c762def..2dba2cb6f0d0f 100644
+--- a/mm/memfd.c
++++ b/mm/memfd.c
+@@ -271,7 +271,8 @@ long memfd_fcntl(struct file *file, unsigned int cmd, unsigned int arg)
+ static int check_sysctl_memfd_noexec(unsigned int *flags)
+ {
+ #ifdef CONFIG_SYSCTL
+-      int sysctl = task_active_pid_ns(current)->memfd_noexec_scope;
++      struct pid_namespace *ns = task_active_pid_ns(current);
++      int sysctl = pidns_memfd_noexec_scope(ns);
+       if (!(*flags & (MFD_EXEC | MFD_NOEXEC_SEAL))) {
+               if (sysctl >= MEMFD_NOEXEC_SCOPE_NOEXEC_SEAL)
+-- 
+2.40.1
+
diff --git a/queue-6.5/mm-memfd-sysctl-fix-memfd_noexec_scope_noexec_enforc.patch b/queue-6.5/mm-memfd-sysctl-fix-memfd_noexec_scope_noexec_enforc.patch
new file mode 100644 (file)
index 0000000..dc4c460
--- /dev/null
@@ -0,0 +1,136 @@
+From 1412a8f4e309ff7a9f8f16cc45fdbae8b93a2bfa Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Jul 2023 06:33:14 +0000
+Subject: mm/memfd: sysctl: fix MEMFD_NOEXEC_SCOPE_NOEXEC_ENFORCED
+
+From: Jeff Xu <jeffxu@google.com>
+
+[ Upstream commit 72de259130229412ca49871e70ffaf17dc9fba98 ]
+
+Patch series "mm/memfd: fix sysctl MEMFD_NOEXEC_SCOPE_NOEXEC_ENFORCED", v2.
+
+When sysctl vm.memfd_noexec is 2 (MEMFD_NOEXEC_SCOPE_NOEXEC_ENFORCED),
+memfd_create(.., MFD_EXEC) should fail.
+
+This complies with how MEMFD_NOEXEC_SCOPE_NOEXEC_ENFORCED is defined -
+"memfd_create() without MFD_NOEXEC_SEAL will be rejected"
+
+Thanks to Dominique Martinet <asmadeus@codewreck.org> who reported the bug.
+see [1] for context.
+
+[1] https://lore.kernel.org/linux-mm/CABi2SkXUX_QqTQ10Yx9bBUGpN1wByOi_=gZU6WEy5a8MaQY3Jw@mail.gmail.com/T/
+
+This patch (of 2):
+
+When vm.memfd_noexec is 2 (MEMFD_NOEXEC_SCOPE_NOEXEC_ENFORCED),
+memfd_create(.., MFD_EXEC) should fail.
+
+This complies with how MEMFD_NOEXEC_SCOPE_NOEXEC_ENFORCED is
+defined - "memfd_create() without MFD_NOEXEC_SEAL will be rejected"
+
+Link: https://lkml.kernel.org/r/20230705063315.3680666-1-jeffxu@google.com
+Link: https://lkml.kernel.org/r/20230705063315.3680666-2-jeffxu@google.com
+Fixes: 105ff5339f49 ("mm/memfd: add MFD_NOEXEC_SEAL and MFD_EXEC")
+Reported-by: Dominique Martinet <asmadeus@codewreck.org>
+Closes: https://lore.kernel.org/linux-mm/CABi2SkXUX_QqTQ10Yx9bBUGpN1wByOi_=gZU6WEy5a8MaQY3Jw@mail.gmail.com/T/
+Reported-by: kernel test robot <lkp@intel.com>
+Closes: https://lore.kernel.org/oe-kbuild-all/202306301351.kkbSegQW-lkp@intel.com/
+Signed-off-by: Jeff Xu <jeffxu@google.com>
+Cc: Daniel Verkamp <dverkamp@chromium.org>
+Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+Cc: Hugh Dickins <hughd@google.com>
+Cc: Jann Horn <jannh@google.com>
+Cc: Jorge Lucangeli Obes <jorgelo@chromium.org>
+Cc: Kees Cook <keescook@chromium.org>
+Cc: Shuah Khan <skhan@linuxfoundation.org>
+Cc: Mike Kravetz <mike.kravetz@oracle.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Stable-dep-of: 202e14222fad ("memfd: do not -EACCES old memfd_create() users with vm.memfd_noexec=2")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ mm/memfd.c | 57 +++++++++++++++++++++++++++++++-----------------------
+ 1 file changed, 33 insertions(+), 24 deletions(-)
+
+diff --git a/mm/memfd.c b/mm/memfd.c
+index e763e76f11064..0bdbd2335af75 100644
+--- a/mm/memfd.c
++++ b/mm/memfd.c
+@@ -268,6 +268,36 @@ long memfd_fcntl(struct file *file, unsigned int cmd, unsigned int arg)
+ #define MFD_ALL_FLAGS (MFD_CLOEXEC | MFD_ALLOW_SEALING | MFD_HUGETLB | MFD_NOEXEC_SEAL | MFD_EXEC)
++static int check_sysctl_memfd_noexec(unsigned int *flags)
++{
++#ifdef CONFIG_SYSCTL
++      char comm[TASK_COMM_LEN];
++      int sysctl = MEMFD_NOEXEC_SCOPE_EXEC;
++      struct pid_namespace *ns;
++
++      ns = task_active_pid_ns(current);
++      if (ns)
++              sysctl = ns->memfd_noexec_scope;
++
++      if (!(*flags & (MFD_EXEC | MFD_NOEXEC_SEAL))) {
++              if (sysctl == MEMFD_NOEXEC_SCOPE_NOEXEC_SEAL)
++                      *flags |= MFD_NOEXEC_SEAL;
++              else
++                      *flags |= MFD_EXEC;
++      }
++
++      if (*flags & MFD_EXEC && sysctl >= MEMFD_NOEXEC_SCOPE_NOEXEC_ENFORCED) {
++              pr_warn_once(
++                      "memfd_create(): MFD_NOEXEC_SEAL is enforced, pid=%d '%s'\n",
++                      task_pid_nr(current), get_task_comm(comm, current));
++
++              return -EACCES;
++      }
++#endif
++
++      return 0;
++}
++
+ SYSCALL_DEFINE2(memfd_create,
+               const char __user *, uname,
+               unsigned int, flags)
+@@ -294,35 +324,14 @@ SYSCALL_DEFINE2(memfd_create,
+               return -EINVAL;
+       if (!(flags & (MFD_EXEC | MFD_NOEXEC_SEAL))) {
+-#ifdef CONFIG_SYSCTL
+-              int sysctl = MEMFD_NOEXEC_SCOPE_EXEC;
+-              struct pid_namespace *ns;
+-
+-              ns = task_active_pid_ns(current);
+-              if (ns)
+-                      sysctl = ns->memfd_noexec_scope;
+-
+-              switch (sysctl) {
+-              case MEMFD_NOEXEC_SCOPE_EXEC:
+-                      flags |= MFD_EXEC;
+-                      break;
+-              case MEMFD_NOEXEC_SCOPE_NOEXEC_SEAL:
+-                      flags |= MFD_NOEXEC_SEAL;
+-                      break;
+-              default:
+-                      pr_warn_once(
+-                              "memfd_create(): MFD_NOEXEC_SEAL is enforced, pid=%d '%s'\n",
+-                              task_pid_nr(current), get_task_comm(comm, current));
+-                      return -EINVAL;
+-              }
+-#else
+-              flags |= MFD_EXEC;
+-#endif
+               pr_warn_once(
+                       "memfd_create() without MFD_EXEC nor MFD_NOEXEC_SEAL, pid=%d '%s'\n",
+                       task_pid_nr(current), get_task_comm(comm, current));
+       }
++      if (check_sysctl_memfd_noexec(&flags) < 0)
++              return -EACCES;
++
+       /* length includes terminating zero */
+       len = strnlen_user(uname, MFD_NAME_MAX_LEN + 1);
+       if (len <= 0)
+-- 
+2.40.1
+
diff --git a/queue-6.5/selftests-memfd-sysctl-fix-memfd_noexec_scope_noexec.patch b/queue-6.5/selftests-memfd-sysctl-fix-memfd_noexec_scope_noexec.patch
new file mode 100644 (file)
index 0000000..277d4cc
--- /dev/null
@@ -0,0 +1,53 @@
+From 5b445b8496df537067328c8ad7a466e90d1442f0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Jul 2023 06:33:15 +0000
+Subject: selftests/memfd: sysctl: fix MEMFD_NOEXEC_SCOPE_NOEXEC_ENFORCED
+
+From: Jeff Xu <jeffxu@google.com>
+
+[ Upstream commit badbbcd76545c58eff64bb1548f7f834a30dc52a ]
+
+Add selftest for sysctl vm.memfd_noexec is 2
+(MEMFD_NOEXEC_SCOPE_NOEXEC_ENFORCED)
+
+memfd_create(.., MFD_EXEC) should fail in this case.
+
+Link: https://lkml.kernel.org/r/20230705063315.3680666-3-jeffxu@google.com
+Reported-by: Dominique Martinet <asmadeus@codewreck.org>
+Closes: https://lore.kernel.org/linux-mm/CABi2SkXUX_QqTQ10Yx9bBUGpN1wByOi_=gZU6WEy5a8MaQY3Jw@mail.gmail.com/T/
+Signed-off-by: Jeff Xu <jeffxu@google.com>
+Cc: Daniel Verkamp <dverkamp@chromium.org>
+Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+Cc: Hugh Dickins <hughd@google.com>
+Cc: Jann Horn <jannh@google.com>
+Cc: Jorge Lucangeli Obes <jorgelo@chromium.org>
+Cc: Kees Cook <keescook@chromium.org>
+Cc: kernel test robot <lkp@intel.com>
+Cc: Mike Kravetz <mike.kravetz@oracle.com>
+Cc: Shuah Khan <skhan@linuxfoundation.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Stable-dep-of: 202e14222fad ("memfd: do not -EACCES old memfd_create() users with vm.memfd_noexec=2")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/testing/selftests/memfd/memfd_test.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/tools/testing/selftests/memfd/memfd_test.c b/tools/testing/selftests/memfd/memfd_test.c
+index 7fc5d7c3bd65b..8eb49204f9eac 100644
+--- a/tools/testing/selftests/memfd/memfd_test.c
++++ b/tools/testing/selftests/memfd/memfd_test.c
+@@ -1147,6 +1147,11 @@ static void test_sysctl_child(void)
+       sysctl_assert_write("2");
+       mfd_fail_new("kern_memfd_sysctl_2",
+               MFD_CLOEXEC | MFD_ALLOW_SEALING);
++      mfd_fail_new("kern_memfd_sysctl_2_MFD_EXEC",
++              MFD_CLOEXEC | MFD_EXEC);
++      fd = mfd_assert_new("", 0, MFD_NOEXEC_SEAL);
++      close(fd);
++
+       sysctl_fail_write("0");
+       sysctl_fail_write("1");
+ }
+-- 
+2.40.1
+
diff --git a/queue-6.5/serial-sc16is7xx-fix-regression-with-gpio-configurat.patch b/queue-6.5/serial-sc16is7xx-fix-regression-with-gpio-configurat.patch
new file mode 100644 (file)
index 0000000..edafde4
--- /dev/null
@@ -0,0 +1,287 @@
+From 5366e2117c73c1ac28959aa4378746028afc7ea9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 7 Aug 2023 17:45:54 -0400
+Subject: serial: sc16is7xx: fix regression with GPIO configuration
+
+From: Hugo Villeneuve <hvilleneuve@dimonoff.com>
+
+[ Upstream commit 0499942928341d572a42199580433c2b0725211e ]
+
+Commit 679875d1d880 ("sc16is7xx: Separate GPIOs from modem control lines")
+and commit 21144bab4f11 ("sc16is7xx: Handle modem status lines")
+changed the function of the GPIOs pins to act as modem control
+lines without any possibility of selecting GPIO function.
+
+As a consequence, applications that depends on GPIO lines configured
+by default as GPIO pins no longer work as expected.
+
+Also, the change to select modem control lines function was done only
+for channel A of dual UART variants (752/762). This was not documented
+in the log message.
+
+Allow to specify GPIO or modem control line function in the device
+tree, and for each of the ports (A or B).
+
+Do so by using the new device-tree property named
+"nxp,modem-control-line-ports" (property added in separate patch).
+
+When registering GPIO chip controller, mask-out GPIO pins declared as
+modem control lines according to this new DT property.
+
+Fixes: 679875d1d880 ("sc16is7xx: Separate GPIOs from modem control lines")
+Fixes: 21144bab4f11 ("sc16is7xx: Handle modem status lines")
+Cc: stable@vger.kernel.org
+Signed-off-by: Hugo Villeneuve <hvilleneuve@dimonoff.com>
+Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
+Reviewed-by: Lech Perczak <lech.perczak@camlingroup.com>
+Tested-by: Lech Perczak <lech.perczak@camlingroup.com>
+Acked-by: Rob Herring <robh@kernel.org>
+Link: https://lore.kernel.org/r/20230807214556.540627-5-hugo@hugovil.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/tty/serial/sc16is7xx.c | 143 +++++++++++++++++++++++++--------
+ 1 file changed, 108 insertions(+), 35 deletions(-)
+
+diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c
+index f714ba3abc980..289ca7d4e5669 100644
+--- a/drivers/tty/serial/sc16is7xx.c
++++ b/drivers/tty/serial/sc16is7xx.c
+@@ -236,7 +236,8 @@
+ /* IOControl register bits (Only 750/760) */
+ #define SC16IS7XX_IOCONTROL_LATCH_BIT (1 << 0) /* Enable input latching */
+-#define SC16IS7XX_IOCONTROL_MODEM_BIT (1 << 1) /* Enable GPIO[7:4] as modem pins */
++#define SC16IS7XX_IOCONTROL_MODEM_A_BIT       (1 << 1) /* Enable GPIO[7:4] as modem A pins */
++#define SC16IS7XX_IOCONTROL_MODEM_B_BIT       (1 << 2) /* Enable GPIO[3:0] as modem B pins */
+ #define SC16IS7XX_IOCONTROL_SRESET_BIT        (1 << 3) /* Software Reset */
+ /* EFCR register bits */
+@@ -301,12 +302,12 @@
+ /* Misc definitions */
+ #define SC16IS7XX_FIFO_SIZE           (64)
+ #define SC16IS7XX_REG_SHIFT           2
++#define SC16IS7XX_GPIOS_PER_BANK      4
+ struct sc16is7xx_devtype {
+       char    name[10];
+       int     nr_gpio;
+       int     nr_uart;
+-      int     has_mctrl;
+ };
+ #define SC16IS7XX_RECONF_MD           (1 << 0)
+@@ -336,7 +337,9 @@ struct sc16is7xx_port {
+       struct clk                      *clk;
+ #ifdef CONFIG_GPIOLIB
+       struct gpio_chip                gpio;
++      unsigned long                   gpio_valid_mask;
+ #endif
++      u8                              mctrl_mask;
+       unsigned char                   buf[SC16IS7XX_FIFO_SIZE];
+       struct kthread_worker           kworker;
+       struct task_struct              *kworker_task;
+@@ -447,35 +450,30 @@ static const struct sc16is7xx_devtype sc16is74x_devtype = {
+       .name           = "SC16IS74X",
+       .nr_gpio        = 0,
+       .nr_uart        = 1,
+-      .has_mctrl      = 0,
+ };
+ static const struct sc16is7xx_devtype sc16is750_devtype = {
+       .name           = "SC16IS750",
+-      .nr_gpio        = 4,
++      .nr_gpio        = 8,
+       .nr_uart        = 1,
+-      .has_mctrl      = 1,
+ };
+ static const struct sc16is7xx_devtype sc16is752_devtype = {
+       .name           = "SC16IS752",
+-      .nr_gpio        = 0,
++      .nr_gpio        = 8,
+       .nr_uart        = 2,
+-      .has_mctrl      = 1,
+ };
+ static const struct sc16is7xx_devtype sc16is760_devtype = {
+       .name           = "SC16IS760",
+-      .nr_gpio        = 4,
++      .nr_gpio        = 8,
+       .nr_uart        = 1,
+-      .has_mctrl      = 1,
+ };
+ static const struct sc16is7xx_devtype sc16is762_devtype = {
+       .name           = "SC16IS762",
+-      .nr_gpio        = 0,
++      .nr_gpio        = 8,
+       .nr_uart        = 2,
+-      .has_mctrl      = 1,
+ };
+ static bool sc16is7xx_regmap_volatile(struct device *dev, unsigned int reg)
+@@ -1357,8 +1355,98 @@ static int sc16is7xx_gpio_direction_output(struct gpio_chip *chip,
+       return 0;
+ }
++
++static int sc16is7xx_gpio_init_valid_mask(struct gpio_chip *chip,
++                                        unsigned long *valid_mask,
++                                        unsigned int ngpios)
++{
++      struct sc16is7xx_port *s = gpiochip_get_data(chip);
++
++      *valid_mask = s->gpio_valid_mask;
++
++      return 0;
++}
++
++static int sc16is7xx_setup_gpio_chip(struct sc16is7xx_port *s)
++{
++      struct device *dev = s->p[0].port.dev;
++
++      if (!s->devtype->nr_gpio)
++              return 0;
++
++      switch (s->mctrl_mask) {
++      case 0:
++              s->gpio_valid_mask = GENMASK(7, 0);
++              break;
++      case SC16IS7XX_IOCONTROL_MODEM_A_BIT:
++              s->gpio_valid_mask = GENMASK(3, 0);
++              break;
++      case SC16IS7XX_IOCONTROL_MODEM_B_BIT:
++              s->gpio_valid_mask = GENMASK(7, 4);
++              break;
++      default:
++              break;
++      }
++
++      if (s->gpio_valid_mask == 0)
++              return 0;
++
++      s->gpio.owner            = THIS_MODULE;
++      s->gpio.parent           = dev;
++      s->gpio.label            = dev_name(dev);
++      s->gpio.init_valid_mask  = sc16is7xx_gpio_init_valid_mask;
++      s->gpio.direction_input  = sc16is7xx_gpio_direction_input;
++      s->gpio.get              = sc16is7xx_gpio_get;
++      s->gpio.direction_output = sc16is7xx_gpio_direction_output;
++      s->gpio.set              = sc16is7xx_gpio_set;
++      s->gpio.base             = -1;
++      s->gpio.ngpio            = s->devtype->nr_gpio;
++      s->gpio.can_sleep        = 1;
++
++      return gpiochip_add_data(&s->gpio, s);
++}
+ #endif
++/*
++ * Configure ports designated to operate as modem control lines.
++ */
++static int sc16is7xx_setup_mctrl_ports(struct sc16is7xx_port *s)
++{
++      int i;
++      int ret;
++      int count;
++      u32 mctrl_port[2];
++      struct device *dev = s->p[0].port.dev;
++
++      count = device_property_count_u32(dev, "nxp,modem-control-line-ports");
++      if (count < 0 || count > ARRAY_SIZE(mctrl_port))
++              return 0;
++
++      ret = device_property_read_u32_array(dev, "nxp,modem-control-line-ports",
++                                           mctrl_port, count);
++      if (ret)
++              return ret;
++
++      s->mctrl_mask = 0;
++
++      for (i = 0; i < count; i++) {
++              /* Use GPIO lines as modem control lines */
++              if (mctrl_port[i] == 0)
++                      s->mctrl_mask |= SC16IS7XX_IOCONTROL_MODEM_A_BIT;
++              else if (mctrl_port[i] == 1)
++                      s->mctrl_mask |= SC16IS7XX_IOCONTROL_MODEM_B_BIT;
++      }
++
++      if (s->mctrl_mask)
++              regmap_update_bits(
++                      s->regmap,
++                      SC16IS7XX_IOCONTROL_REG << SC16IS7XX_REG_SHIFT,
++                      SC16IS7XX_IOCONTROL_MODEM_A_BIT |
++                      SC16IS7XX_IOCONTROL_MODEM_B_BIT, s->mctrl_mask);
++
++      return 0;
++}
++
+ static const struct serial_rs485 sc16is7xx_rs485_supported = {
+       .flags = SER_RS485_ENABLED | SER_RS485_RTS_AFTER_SEND,
+       .delay_rts_before_send = 1,
+@@ -1471,12 +1559,6 @@ static int sc16is7xx_probe(struct device *dev,
+                                    SC16IS7XX_EFCR_RXDISABLE_BIT |
+                                    SC16IS7XX_EFCR_TXDISABLE_BIT);
+-              /* Use GPIO lines as modem status registers */
+-              if (devtype->has_mctrl)
+-                      sc16is7xx_port_write(&s->p[i].port,
+-                                           SC16IS7XX_IOCONTROL_REG,
+-                                           SC16IS7XX_IOCONTROL_MODEM_BIT);
+-
+               /* Initialize kthread work structs */
+               kthread_init_work(&s->p[i].tx_work, sc16is7xx_tx_proc);
+               kthread_init_work(&s->p[i].reg_work, sc16is7xx_reg_proc);
+@@ -1514,23 +1596,14 @@ static int sc16is7xx_probe(struct device *dev,
+                               s->p[u].irda_mode = true;
+       }
++      ret = sc16is7xx_setup_mctrl_ports(s);
++      if (ret)
++              goto out_ports;
++
+ #ifdef CONFIG_GPIOLIB
+-      if (devtype->nr_gpio) {
+-              /* Setup GPIO cotroller */
+-              s->gpio.owner            = THIS_MODULE;
+-              s->gpio.parent           = dev;
+-              s->gpio.label            = dev_name(dev);
+-              s->gpio.direction_input  = sc16is7xx_gpio_direction_input;
+-              s->gpio.get              = sc16is7xx_gpio_get;
+-              s->gpio.direction_output = sc16is7xx_gpio_direction_output;
+-              s->gpio.set              = sc16is7xx_gpio_set;
+-              s->gpio.base             = -1;
+-              s->gpio.ngpio            = devtype->nr_gpio;
+-              s->gpio.can_sleep        = 1;
+-              ret = gpiochip_add_data(&s->gpio, s);
+-              if (ret)
+-                      goto out_ports;
+-      }
++      ret = sc16is7xx_setup_gpio_chip(s);
++      if (ret)
++              goto out_ports;
+ #endif
+       /*
+@@ -1553,7 +1626,7 @@ static int sc16is7xx_probe(struct device *dev,
+               return 0;
+ #ifdef CONFIG_GPIOLIB
+-      if (devtype->nr_gpio)
++      if (s->gpio_valid_mask)
+               gpiochip_remove(&s->gpio);
+ #endif
+@@ -1577,7 +1650,7 @@ static void sc16is7xx_remove(struct device *dev)
+       int i;
+ #ifdef CONFIG_GPIOLIB
+-      if (s->devtype->nr_gpio)
++      if (s->gpio_valid_mask)
+               gpiochip_remove(&s->gpio);
+ #endif
+-- 
+2.40.1
+
diff --git a/queue-6.5/serial-sc16is7xx-remove-obsolete-out_thread-label.patch b/queue-6.5/serial-sc16is7xx-remove-obsolete-out_thread-label.patch
new file mode 100644 (file)
index 0000000..8862bc9
--- /dev/null
@@ -0,0 +1,57 @@
+From 2455e3fd8a3a90a6cabdf482675122482a566bdb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 7 Aug 2023 17:45:52 -0400
+Subject: serial: sc16is7xx: remove obsolete out_thread label
+
+From: Hugo Villeneuve <hvilleneuve@dimonoff.com>
+
+[ Upstream commit dabc54a45711fe77674a6c0348231e00e66bd567 ]
+
+Commit c8f71b49ee4d ("serial: sc16is7xx: setup GPIO controller later
+in probe") moved GPIO setup code later in probe function. Doing so
+also required to move ports cleanup code (out_ports label) after the
+GPIO cleanup code.
+
+After these moves, the out_thread label becomes misplaced and makes
+part of the cleanup code illogical.
+
+This patch remove the now obsolete out_thread label and make GPIO
+setup code jump to out_ports label if it fails.
+
+Signed-off-by: Hugo Villeneuve <hvilleneuve@dimonoff.com>
+Reviewed-by: Lech Perczak <lech.perczak@camlingroup.com>
+Tested-by: Lech Perczak <lech.perczak@camlingroup.com>
+Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
+Link: https://lore.kernel.org/r/20230807214556.540627-3-hugo@hugovil.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: 049994292834 ("serial: sc16is7xx: fix regression with GPIO configuration")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/tty/serial/sc16is7xx.c | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c
+index faeb3dc371c05..f714ba3abc980 100644
+--- a/drivers/tty/serial/sc16is7xx.c
++++ b/drivers/tty/serial/sc16is7xx.c
+@@ -1529,7 +1529,7 @@ static int sc16is7xx_probe(struct device *dev,
+               s->gpio.can_sleep        = 1;
+               ret = gpiochip_add_data(&s->gpio, s);
+               if (ret)
+-                      goto out_thread;
++                      goto out_ports;
+       }
+ #endif
+@@ -1555,8 +1555,6 @@ static int sc16is7xx_probe(struct device *dev,
+ #ifdef CONFIG_GPIOLIB
+       if (devtype->nr_gpio)
+               gpiochip_remove(&s->gpio);
+-
+-out_thread:
+ #endif
+ out_ports:
+-- 
+2.40.1
+
index 0664d95acfca5fb1266967eb78fbb357d3f3b6cf..386d71654457aa007aad17a912ac364e69e79af2 100644 (file)
@@ -720,3 +720,12 @@ crypto-stm32-fix-loop-iterating-through-scatterlist-for-dma.patch
 crypto-stm32-fix-mdmat-condition.patch
 cpufreq-brcmstb-avs-cpufreq-fix-warray-bounds-bug.patch
 of-property-fw_devlink-add-a-devlink-for-panel-followers.patch
+bluetooth-msft-extended-monitor-tracking-by-address-.patch
+bluetooth-hci-introduce-hci_quirk_broken_le_coded.patch
+serial-sc16is7xx-remove-obsolete-out_thread-label.patch
+serial-sc16is7xx-fix-regression-with-gpio-configurat.patch
+mm-memfd-sysctl-fix-memfd_noexec_scope_noexec_enforc.patch
+selftests-memfd-sysctl-fix-memfd_noexec_scope_noexec.patch
+memfd-do-not-eacces-old-memfd_create-users-with-vm.m.patch
+memfd-replace-ratcheting-feature-from-vm.memfd_noexe.patch
+memfd-improve-userspace-warnings-for-missing-exec-re.patch