From: Sasha Levin Date: Sun, 10 Sep 2023 14:39:21 +0000 (-0400) Subject: Fixes for 6.5 X-Git-Tag: v6.1.53~41 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=a2ae9c9cc36b0ca8b10f049bb9d8217abe00058f;p=thirdparty%2Fkernel%2Fstable-queue.git Fixes for 6.5 Signed-off-by: Sasha Levin --- 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 index 00000000000..f28e904c791 --- /dev/null +++ b/queue-6.5/bluetooth-hci-introduce-hci_quirk_broken_le_coded.patch @@ -0,0 +1,106 @@ +From e0e4a169311075ab305352546fb07bded269bdf2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 22 Aug 2023 12:02:03 -0700 +Subject: Bluetooth: HCI: Introduce HCI_QUIRK_BROKEN_LE_CODED + +From: Luiz Augusto von Dentz + +[ 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 +Signed-off-by: Sasha Levin +--- + 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 index 00000000000..c2d93874ee3 --- /dev/null +++ b/queue-6.5/bluetooth-msft-extended-monitor-tracking-by-address-.patch @@ -0,0 +1,669 @@ +From 929cbac299030c0d174e676d1e5de403e313d920 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jun 2023 18:00:31 +0800 +Subject: Bluetooth: msft: Extended monitor tracking by address filter + +From: Hilda Wu + +[ 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 +Signed-off-by: Hilda Wu +Reviewed-by: Simon Horman +Signed-off-by: Luiz Augusto von Dentz +Stable-dep-of: 253f3399f4c0 ("Bluetooth: HCI: Introduce HCI_QUIRK_BROKEN_LE_CODED") +Signed-off-by: Sasha Levin +--- + 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 index 00000000000..9bc45cc2246 --- /dev/null +++ b/queue-6.5/memfd-do-not-eacces-old-memfd_create-users-with-vm.m.patch @@ -0,0 +1,177 @@ +From 517ab256434dcf02b8d41c12db9ceedff3308dae Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Cc: Dominique Martinet +Cc: Christian Brauner +Cc: Daniel Verkamp +Cc: Jeff Xu +Cc: Kees Cook +Cc: Shuah Khan +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + 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 index 00000000000..1d5d63f18bc --- /dev/null +++ b/queue-6.5/memfd-improve-userspace-warnings-for-missing-exec-re.patch @@ -0,0 +1,66 @@ +From a6229d573525387fc64572add866a2d741cf4f09 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 14 Aug 2023 18:40:59 +1000 +Subject: memfd: improve userspace warnings for missing exec-related flags + +From: Aleksa Sarai + +[ 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 +Cc: Christian Brauner +Cc: Daniel Verkamp +Cc: Dominique Martinet +Cc: Kees Cook +Cc: Shuah Khan +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + 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 index 00000000000..9f7f43215e3 --- /dev/null +++ b/queue-6.5/memfd-replace-ratcheting-feature-from-vm.memfd_noexe.patch @@ -0,0 +1,283 @@ +From 22d1ba33bed48f4fe6feffac9c0e64bd47c83432 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 14 Aug 2023 18:41:00 +1000 +Subject: memfd: replace ratcheting feature from vm.memfd_noexec with hierarchy + +From: Aleksa Sarai + +[ 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 + #include + #include + #include + #include + #include + + #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 +Cc: Dominique Martinet +Cc: Christian Brauner +Cc: Daniel Verkamp +Cc: Jeff Xu +Cc: Kees Cook +Cc: Shuah Khan +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + 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 + + #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 index 00000000000..dc4c4606a78 --- /dev/null +++ b/queue-6.5/mm-memfd-sysctl-fix-memfd_noexec_scope_noexec_enforc.patch @@ -0,0 +1,136 @@ +From 1412a8f4e309ff7a9f8f16cc45fdbae8b93a2bfa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 5 Jul 2023 06:33:14 +0000 +Subject: mm/memfd: sysctl: fix MEMFD_NOEXEC_SCOPE_NOEXEC_ENFORCED + +From: Jeff Xu + +[ 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 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 +Closes: https://lore.kernel.org/linux-mm/CABi2SkXUX_QqTQ10Yx9bBUGpN1wByOi_=gZU6WEy5a8MaQY3Jw@mail.gmail.com/T/ +Reported-by: kernel test robot +Closes: https://lore.kernel.org/oe-kbuild-all/202306301351.kkbSegQW-lkp@intel.com/ +Signed-off-by: Jeff Xu +Cc: Daniel Verkamp +Cc: Dmitry Torokhov +Cc: Hugh Dickins +Cc: Jann Horn +Cc: Jorge Lucangeli Obes +Cc: Kees Cook +Cc: Shuah Khan +Cc: Mike Kravetz +Signed-off-by: Andrew Morton +Stable-dep-of: 202e14222fad ("memfd: do not -EACCES old memfd_create() users with vm.memfd_noexec=2") +Signed-off-by: Sasha Levin +--- + 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 index 00000000000..277d4cc0e67 --- /dev/null +++ b/queue-6.5/selftests-memfd-sysctl-fix-memfd_noexec_scope_noexec.patch @@ -0,0 +1,53 @@ +From 5b445b8496df537067328c8ad7a466e90d1442f0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 5 Jul 2023 06:33:15 +0000 +Subject: selftests/memfd: sysctl: fix MEMFD_NOEXEC_SCOPE_NOEXEC_ENFORCED + +From: Jeff Xu + +[ 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 +Closes: https://lore.kernel.org/linux-mm/CABi2SkXUX_QqTQ10Yx9bBUGpN1wByOi_=gZU6WEy5a8MaQY3Jw@mail.gmail.com/T/ +Signed-off-by: Jeff Xu +Cc: Daniel Verkamp +Cc: Dmitry Torokhov +Cc: Hugh Dickins +Cc: Jann Horn +Cc: Jorge Lucangeli Obes +Cc: Kees Cook +Cc: kernel test robot +Cc: Mike Kravetz +Cc: Shuah Khan +Signed-off-by: Andrew Morton +Stable-dep-of: 202e14222fad ("memfd: do not -EACCES old memfd_create() users with vm.memfd_noexec=2") +Signed-off-by: Sasha Levin +--- + 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 index 00000000000..edafde45a9c --- /dev/null +++ b/queue-6.5/serial-sc16is7xx-fix-regression-with-gpio-configurat.patch @@ -0,0 +1,287 @@ +From 5366e2117c73c1ac28959aa4378746028afc7ea9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 7 Aug 2023 17:45:54 -0400 +Subject: serial: sc16is7xx: fix regression with GPIO configuration + +From: Hugo Villeneuve + +[ 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 +Reviewed-by: Andy Shevchenko +Reviewed-by: Lech Perczak +Tested-by: Lech Perczak +Acked-by: Rob Herring +Link: https://lore.kernel.org/r/20230807214556.540627-5-hugo@hugovil.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + 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 index 00000000000..8862bc9dcd6 --- /dev/null +++ b/queue-6.5/serial-sc16is7xx-remove-obsolete-out_thread-label.patch @@ -0,0 +1,57 @@ +From 2455e3fd8a3a90a6cabdf482675122482a566bdb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 7 Aug 2023 17:45:52 -0400 +Subject: serial: sc16is7xx: remove obsolete out_thread label + +From: Hugo Villeneuve + +[ 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 +Reviewed-by: Lech Perczak +Tested-by: Lech Perczak +Reviewed-by: Andy Shevchenko +Link: https://lore.kernel.org/r/20230807214556.540627-3-hugo@hugovil.com +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: 049994292834 ("serial: sc16is7xx: fix regression with GPIO configuration") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.5/series b/queue-6.5/series index 0664d95acfc..386d7165445 100644 --- a/queue-6.5/series +++ b/queue-6.5/series @@ -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