diff options
Diffstat (limited to 'SOURCES/patch-6.7-redhat.patch')
-rw-r--r-- | SOURCES/patch-6.7-redhat.patch | 743 |
1 files changed, 700 insertions, 43 deletions
diff --git a/SOURCES/patch-6.7-redhat.patch b/SOURCES/patch-6.7-redhat.patch index c7bea04..8ba4339 100644 --- a/SOURCES/patch-6.7-redhat.patch +++ b/SOURCES/patch-6.7-redhat.patch @@ -1,3 +1,4 @@ + .../admin-guide/laptops/thinkpad-acpi.rst | 7 +- Makefile | 20 ++- arch/s390/include/asm/ipl.h | 1 + arch/s390/kernel/ipl.c | 5 + @@ -13,15 +14,25 @@ drivers/firmware/efi/efi.c | 124 +++++++++++---- drivers/firmware/efi/secureboot.c | 38 +++++ drivers/firmware/sysfb.c | 18 ++- + drivers/gpu/drm/amd/amdgpu/amdgpu.h | 2 + + drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c | 15 ++ + drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 12 +- + drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c | 9 +- drivers/hid/hid-rmi.c | 66 -------- drivers/hwtracing/coresight/coresight-etm4x-core.c | 19 +++ - drivers/input/keyboard/atkbd.c | 14 +- + drivers/input/keyboard/atkbd.c | 3 +- drivers/input/rmi4/rmi_driver.c | 124 +++++++++------ drivers/iommu/iommu.c | 22 +++ + drivers/md/dm-core.h | 2 + + drivers/md/dm-ioctl.c | 3 +- + drivers/md/dm-table.c | 9 +- drivers/net/wireless/ath/ath10k/wmi-tlv.c | 4 + drivers/pci/quirks.c | 24 +++ + drivers/platform/x86/thinkpad_acpi.c | 20 ++- drivers/scsi/sd.c | 10 ++ drivers/usb/core/hub.c | 7 + + fs/btrfs/transaction.c | 38 +---- + fs/smb/client/namespace.c | 16 ++ include/linux/efi.h | 22 ++- include/linux/lsm_hook_defs.h | 2 + include/linux/module.h | 1 + @@ -30,6 +41,7 @@ include/linux/security.h | 5 + kernel/module/main.c | 2 + kernel/module/signing.c | 9 +- + net/openvswitch/flow_netlink.c | 49 ++++-- scripts/mod/modpost.c | 8 + scripts/tags.sh | 2 + security/integrity/platform_certs/load_uefi.c | 6 +- @@ -37,10 +49,37 @@ security/lockdown/lockdown.c | 1 + security/security.c | 12 ++ tools/power/cpupower/Makefile | 2 +- - 39 files changed, 683 insertions(+), 181 deletions(-) + .../selftests/net/openvswitch/openvswitch.sh | 13 ++ + .../testing/selftests/net/openvswitch/ovs-dpctl.py | 71 +++++++-- + 53 files changed, 866 insertions(+), 253 deletions(-) +diff --git a/Documentation/admin-guide/laptops/thinkpad-acpi.rst b/Documentation/admin-guide/laptops/thinkpad-acpi.rst +index 98d304010170..7f674a6cfa8a 100644 +--- a/Documentation/admin-guide/laptops/thinkpad-acpi.rst ++++ b/Documentation/admin-guide/laptops/thinkpad-acpi.rst +@@ -444,7 +444,9 @@ event code Key Notes + + 0x1008 0x07 FN+F8 IBM: toggle screen expand + Lenovo: configure UltraNav, +- or toggle screen expand ++ or toggle screen expand. ++ On newer platforms (2024+) ++ replaced by 0x131f (see below) + + 0x1009 0x08 FN+F9 - + +@@ -504,6 +506,9 @@ event code Key Notes + + 0x1019 0x18 unknown + ++0x131f ... FN+F8 Platform Mode change. ++ Implemented in driver. ++ + ... ... ... + + 0x1020 0x1F unknown diff --git a/Makefile b/Makefile -index 73a208d9d4c4..cfff9444b6ab 100644 +index 0f5bb9ddc98f..a46f4937fa26 100644 --- a/Makefile +++ b/Makefile @@ -22,6 +22,18 @@ $(if $(filter __%, $(MAKECMDGOALS)), \ @@ -580,6 +619,113 @@ index 3c197db42c9d..16e4a2e90fae 100644 pd = sysfb_create_simplefb(si, &mode); if (!IS_ERR(pd)) goto unlock_mutex; +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h +index 50f57d4dfd8f..f65a1518546e 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h +@@ -1509,9 +1509,11 @@ static inline int amdgpu_acpi_smart_shift_update(struct drm_device *dev, + #if defined(CONFIG_ACPI) && defined(CONFIG_SUSPEND) + bool amdgpu_acpi_is_s3_active(struct amdgpu_device *adev); + bool amdgpu_acpi_is_s0ix_active(struct amdgpu_device *adev); ++void amdgpu_choose_low_power_state(struct amdgpu_device *adev); + #else + static inline bool amdgpu_acpi_is_s0ix_active(struct amdgpu_device *adev) { return false; } + static inline bool amdgpu_acpi_is_s3_active(struct amdgpu_device *adev) { return false; } ++static void amdgpu_choose_low_power_state(struct amdgpu_device *adev) { } + #endif + + #if defined(CONFIG_DRM_AMD_DC) +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c +index 2deebece810e..cc21ed67a330 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c +@@ -1519,4 +1519,19 @@ bool amdgpu_acpi_is_s0ix_active(struct amdgpu_device *adev) + #endif /* CONFIG_AMD_PMC */ + } + ++/** ++ * amdgpu_choose_low_power_state ++ * ++ * @adev: amdgpu_device_pointer ++ * ++ * Choose the target low power state for the GPU ++ */ ++void amdgpu_choose_low_power_state(struct amdgpu_device *adev) ++{ ++ if (amdgpu_acpi_is_s0ix_active(adev)) ++ adev->in_s0ix = true; ++ else if (amdgpu_acpi_is_s3_active(adev)) ++ adev->in_s3 = true; ++} ++ + #endif /* CONFIG_SUSPEND */ +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +index 5fe1df95dc38..7f48c7ec4136 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +@@ -4441,13 +4441,15 @@ int amdgpu_device_prepare(struct drm_device *dev) + struct amdgpu_device *adev = drm_to_adev(dev); + int i, r; + ++ amdgpu_choose_low_power_state(adev); ++ + if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) + return 0; + + /* Evict the majority of BOs before starting suspend sequence */ + r = amdgpu_device_evict_resources(adev); + if (r) +- return r; ++ goto unprepare; + + for (i = 0; i < adev->num_ip_blocks; i++) { + if (!adev->ip_blocks[i].status.valid) +@@ -4456,10 +4458,15 @@ int amdgpu_device_prepare(struct drm_device *dev) + continue; + r = adev->ip_blocks[i].version->funcs->prepare_suspend((void *)adev); + if (r) +- return r; ++ goto unprepare; + } + + return 0; ++ ++unprepare: ++ adev->in_s0ix = adev->in_s3 = false; ++ ++ return r; + } + + /** +@@ -4496,7 +4503,6 @@ int amdgpu_device_suspend(struct drm_device *dev, bool fbcon) + drm_fb_helper_set_suspend_unlocked(adev_to_drm(adev)->fb_helper, true); + + cancel_delayed_work_sync(&adev->delayed_init_work); +- flush_delayed_work(&adev->gfx.gfx_off_delay_work); + + amdgpu_ras_suspend(adev); + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c +index b9674c57c436..6ddc8e3360e2 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c +@@ -723,8 +723,15 @@ void amdgpu_gfx_off_ctrl(struct amdgpu_device *adev, bool enable) + + if (adev->gfx.gfx_off_req_count == 0 && + !adev->gfx.gfx_off_state) { +- schedule_delayed_work(&adev->gfx.gfx_off_delay_work, ++ /* If going to s2idle, no need to wait */ ++ if (adev->in_s0ix) { ++ if (!amdgpu_dpm_set_powergating_by_smu(adev, ++ AMD_IP_BLOCK_TYPE_GFX, true)) ++ adev->gfx.gfx_off_state = true; ++ } else { ++ schedule_delayed_work(&adev->gfx.gfx_off_delay_work, + delay); ++ } + } + } else { + if (adev->gfx.gfx_off_req_count == 0) { diff --git a/drivers/hid/hid-rmi.c b/drivers/hid/hid-rmi.c index d4af17fdba46..154f0403cbf4 100644 --- a/drivers/hid/hid-rmi.c @@ -734,52 +880,19 @@ index 34aee59dd147..7c5a7f7c11bd 100644 platform_driver_unregister(&etm4_platform_driver); etm4_pm_clear(); diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c -index 13ef6284223d..7f67f9f2946b 100644 +index c229bd6b3f7f..7f67f9f2946b 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c -@@ -811,7 +811,6 @@ static int atkbd_probe(struct atkbd *atkbd) - { - struct ps2dev *ps2dev = &atkbd->ps2dev; - unsigned char param[2]; -- bool skip_getid; - - /* - * Some systems, where the bit-twiddling when testing the io-lines of the -@@ -825,6 +824,11 @@ static int atkbd_probe(struct atkbd *atkbd) - "keyboard reset failed on %s\n", - ps2dev->serio->phys); +@@ -826,7 +826,7 @@ static int atkbd_probe(struct atkbd *atkbd) -+ if (atkbd_skip_getid(atkbd)) { -+ atkbd->id = 0xab83; + if (atkbd_skip_getid(atkbd)) { + atkbd->id = 0xab83; +- return 0; + goto deactivate_kbd; -+ } -+ - /* - * Then we check the keyboard ID. We should get 0xab83 under normal conditions. - * Some keyboards report different values, but the first byte is always 0xab or -@@ -833,18 +837,17 @@ static int atkbd_probe(struct atkbd *atkbd) - */ - - param[0] = param[1] = 0xa5; /* initialize with invalid values */ -- skip_getid = atkbd_skip_getid(atkbd); -- if (skip_getid || ps2_command(ps2dev, param, ATKBD_CMD_GETID)) { -+ if (ps2_command(ps2dev, param, ATKBD_CMD_GETID)) { - - /* -- * If the get ID command was skipped or failed, we check if we can at least set -+ * If the get ID command failed, we check if we can at least set - * the LEDs on the keyboard. This should work on every keyboard out there. - * It also turns the LEDs off, which we want anyway. - */ - param[0] = 0; - if (ps2_command(ps2dev, param, ATKBD_CMD_SETLEDS)) - return -1; -- atkbd->id = skip_getid ? 0xab83 : 0xabba; -+ atkbd->id = 0xabba; - return 0; } -@@ -860,6 +863,7 @@ static int atkbd_probe(struct atkbd *atkbd) + /* +@@ -863,6 +863,7 @@ static int atkbd_probe(struct atkbd *atkbd) return -1; } @@ -1019,6 +1132,60 @@ index 33e2a9b5d339..6ae1abc3f11c 100644 /** * iommu_setup_default_domain - Set the default_domain for the group * @group: Group to change +diff --git a/drivers/md/dm-core.h b/drivers/md/dm-core.h +index 095b9b49aa82..e6757a30dcca 100644 +--- a/drivers/md/dm-core.h ++++ b/drivers/md/dm-core.h +@@ -22,6 +22,8 @@ + #include "dm-ima.h" + + #define DM_RESERVED_MAX_IOS 1024 ++#define DM_MAX_TARGETS 1048576 ++#define DM_MAX_TARGET_PARAMS 1024 + + struct dm_io; + +diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c +index e65058e0ed06..3b1ad7127cb8 100644 +--- a/drivers/md/dm-ioctl.c ++++ b/drivers/md/dm-ioctl.c +@@ -1941,7 +1941,8 @@ static int copy_params(struct dm_ioctl __user *user, struct dm_ioctl *param_kern + minimum_data_size - sizeof(param_kernel->version))) + return -EFAULT; + +- if (param_kernel->data_size < minimum_data_size) { ++ if (unlikely(param_kernel->data_size < minimum_data_size) || ++ unlikely(param_kernel->data_size > DM_MAX_TARGETS * DM_MAX_TARGET_PARAMS)) { + DMERR("Invalid data size in the ioctl structure: %u", + param_kernel->data_size); + return -EINVAL; +diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c +index 198d38b53322..08c9c20f9c66 100644 +--- a/drivers/md/dm-table.c ++++ b/drivers/md/dm-table.c +@@ -129,7 +129,12 @@ static int alloc_targets(struct dm_table *t, unsigned int num) + int dm_table_create(struct dm_table **result, blk_mode_t mode, + unsigned int num_targets, struct mapped_device *md) + { +- struct dm_table *t = kzalloc(sizeof(*t), GFP_KERNEL); ++ struct dm_table *t; ++ ++ if (num_targets > DM_MAX_TARGETS) ++ return -EOVERFLOW; ++ ++ t = kzalloc(sizeof(*t), GFP_KERNEL); + + if (!t) + return -ENOMEM; +@@ -144,7 +149,7 @@ int dm_table_create(struct dm_table **result, blk_mode_t mode, + + if (!num_targets) { + kfree(t); +- return -ENOMEM; ++ return -EOVERFLOW; + } + + if (alloc_targets(t, num_targets)) { diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 6b6aa3c36744..0ce08e9a0a3d 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -1069,6 +1236,51 @@ index a2bf6de11462..692a9e777d72 100644 /* * Intersil/Techwell TW686[4589]-based video capture cards have an empty (zero) * class code. Fix it. +diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c +index c4895e9bc714..ceb22f8d8442 100644 +--- a/drivers/platform/x86/thinkpad_acpi.c ++++ b/drivers/platform/x86/thinkpad_acpi.c +@@ -166,6 +166,7 @@ enum tpacpi_hkey_event_t { + TP_HKEY_EV_VOL_MUTE = 0x1017, /* Mixer output mute */ + TP_HKEY_EV_PRIVACYGUARD_TOGGLE = 0x130f, /* Toggle priv.guard on/off */ + TP_HKEY_EV_AMT_TOGGLE = 0x131a, /* Toggle AMT on/off */ ++ TP_HKEY_EV_PROFILE_TOGGLE = 0x131f, /* Toggle platform profile */ + + /* Reasons for waking up from S3/S4 */ + TP_HKEY_EV_WKUP_S3_UNDOCK = 0x2304, /* undock requested, S3 */ +@@ -3731,6 +3732,7 @@ static bool hotkey_notify_extended_hotkey(const u32 hkey) + switch (hkey) { + case TP_HKEY_EV_PRIVACYGUARD_TOGGLE: + case TP_HKEY_EV_AMT_TOGGLE: ++ case TP_HKEY_EV_PROFILE_TOGGLE: + tpacpi_driver_event(hkey); + return true; + } +@@ -11118,7 +11120,23 @@ static void tpacpi_driver_event(const unsigned int hkey_event) + else + dytc_control_amt(!dytc_amt_active); + } +- ++ if (hkey_event == TP_HKEY_EV_PROFILE_TOGGLE) { ++ switch (dytc_current_profile) { ++ case PLATFORM_PROFILE_LOW_POWER: ++ dytc_profile_set(NULL, PLATFORM_PROFILE_BALANCED); ++ break; ++ case PLATFORM_PROFILE_BALANCED: ++ dytc_profile_set(NULL, PLATFORM_PROFILE_PERFORMANCE); ++ break; ++ case PLATFORM_PROFILE_PERFORMANCE: ++ dytc_profile_set(NULL, PLATFORM_PROFILE_LOW_POWER); ++ break; ++ default: ++ pr_warn("Profile HKEY unexpected profile %d", dytc_current_profile); ++ } ++ /* Notify user space the profile changed */ ++ platform_profile_notify(); ++ } + } + + static void hotkey_driver_event(const unsigned int scancode) diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 542a4bbb21bc..62161ceed2e2 100644 --- a/drivers/scsi/sd.c @@ -1115,6 +1327,103 @@ index ef8d9bda94ac..3fab06f3b43e 100644 /* Lock the device, then check to see if we were * disconnected while waiting for the lock to succeed. */ usb_lock_device(hdev); +diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c +index 5b3333ceef04..c52807d97efa 100644 +--- a/fs/btrfs/transaction.c ++++ b/fs/btrfs/transaction.c +@@ -564,56 +564,22 @@ static int btrfs_reserve_trans_metadata(struct btrfs_fs_info *fs_info, + u64 num_bytes, + u64 *delayed_refs_bytes) + { +- struct btrfs_block_rsv *delayed_refs_rsv = &fs_info->delayed_refs_rsv; + struct btrfs_space_info *si = fs_info->trans_block_rsv.space_info; +- u64 extra_delayed_refs_bytes = 0; +- u64 bytes; ++ u64 bytes = num_bytes + *delayed_refs_bytes; + int ret; + +- /* +- * If there's a gap between the size of the delayed refs reserve and +- * its reserved space, than some tasks have added delayed refs or bumped +- * its size otherwise (due to block group creation or removal, or block +- * group item update). Also try to allocate that gap in order to prevent +- * using (and possibly abusing) the global reserve when committing the +- * transaction. +- */ +- if (flush == BTRFS_RESERVE_FLUSH_ALL && +- !btrfs_block_rsv_full(delayed_refs_rsv)) { +- spin_lock(&delayed_refs_rsv->lock); +- if (delayed_refs_rsv->size > delayed_refs_rsv->reserved) +- extra_delayed_refs_bytes = delayed_refs_rsv->size - +- delayed_refs_rsv->reserved; +- spin_unlock(&delayed_refs_rsv->lock); +- } +- +- bytes = num_bytes + *delayed_refs_bytes + extra_delayed_refs_bytes; +- + /* + * We want to reserve all the bytes we may need all at once, so we only + * do 1 enospc flushing cycle per transaction start. + */ + ret = btrfs_reserve_metadata_bytes(fs_info, si, bytes, flush); +- if (ret == 0) { +- if (extra_delayed_refs_bytes > 0) +- btrfs_migrate_to_delayed_refs_rsv(fs_info, +- extra_delayed_refs_bytes); +- return 0; +- } +- +- if (extra_delayed_refs_bytes > 0) { +- bytes -= extra_delayed_refs_bytes; +- ret = btrfs_reserve_metadata_bytes(fs_info, si, bytes, flush); +- if (ret == 0) +- return 0; +- } + + /* + * If we are an emergency flush, which can steal from the global block + * reserve, then attempt to not reserve space for the delayed refs, as + * we will consume space for them from the global block reserve. + */ +- if (flush == BTRFS_RESERVE_FLUSH_ALL_STEAL) { ++ if (ret && flush == BTRFS_RESERVE_FLUSH_ALL_STEAL) { + bytes -= *delayed_refs_bytes; + *delayed_refs_bytes = 0; + ret = btrfs_reserve_metadata_bytes(fs_info, si, bytes, flush); +diff --git a/fs/smb/client/namespace.c b/fs/smb/client/namespace.c +index a6968573b775..4a517b280f2b 100644 +--- a/fs/smb/client/namespace.c ++++ b/fs/smb/client/namespace.c +@@ -168,6 +168,21 @@ static char *automount_fullpath(struct dentry *dentry, void *page) + return s; + } + ++static void fs_context_set_ids(struct smb3_fs_context *ctx) ++{ ++ kuid_t uid = current_fsuid(); ++ kgid_t gid = current_fsgid(); ++ ++ if (ctx->multiuser) { ++ if (!ctx->uid_specified) ++ ctx->linux_uid = uid; ++ if (!ctx->gid_specified) ++ ctx->linux_gid = gid; ++ } ++ if (!ctx->cruid_specified) ++ ctx->cred_uid = uid; ++} ++ + /* + * Create a vfsmount that we can automount + */ +@@ -205,6 +220,7 @@ static struct vfsmount *cifs_do_automount(struct path *path) + tmp.leaf_fullpath = NULL; + tmp.UNC = tmp.prepath = NULL; + tmp.dfs_root_ses = NULL; ++ fs_context_set_ids(&tmp); + + rc = smb3_fs_context_dup(ctx, &tmp); + if (rc) { diff --git a/include/linux/efi.h b/include/linux/efi.h index 9cc5bf32f6f2..7462fb1fc99e 100644 --- a/include/linux/efi.h @@ -1464,6 +1773,181 @@ index a2ff4242e623..f0d2be1ee4f1 100644 } int module_sig_check(struct load_info *info, int flags) +diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c +index 88965e2068ac..ebc5728aab4e 100644 +--- a/net/openvswitch/flow_netlink.c ++++ b/net/openvswitch/flow_netlink.c +@@ -48,6 +48,7 @@ struct ovs_len_tbl { + + #define OVS_ATTR_NESTED -1 + #define OVS_ATTR_VARIABLE -2 ++#define OVS_COPY_ACTIONS_MAX_DEPTH 16 + + static bool actions_may_change_flow(const struct nlattr *actions) + { +@@ -2545,13 +2546,15 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr, + const struct sw_flow_key *key, + struct sw_flow_actions **sfa, + __be16 eth_type, __be16 vlan_tci, +- u32 mpls_label_count, bool log); ++ u32 mpls_label_count, bool log, ++ u32 depth); + + static int validate_and_copy_sample(struct net *net, const struct nlattr *attr, + const struct sw_flow_key *key, + struct sw_flow_actions **sfa, + __be16 eth_type, __be16 vlan_tci, +- u32 mpls_label_count, bool log, bool last) ++ u32 mpls_label_count, bool log, bool last, ++ u32 depth) + { + const struct nlattr *attrs[OVS_SAMPLE_ATTR_MAX + 1]; + const struct nlattr *probability, *actions; +@@ -2602,7 +2605,8 @@ static int validate_and_copy_sample(struct net *net, const struct nlattr *attr, + return err; + + err = __ovs_nla_copy_actions(net, actions, key, sfa, +- eth_type, vlan_tci, mpls_label_count, log); ++ eth_type, vlan_tci, mpls_label_count, log, ++ depth + 1); + + if (err) + return err; +@@ -2617,7 +2621,8 @@ static int validate_and_copy_dec_ttl(struct net *net, + const struct sw_flow_key *key, + struct sw_flow_actions **sfa, + __be16 eth_type, __be16 vlan_tci, +- u32 mpls_label_count, bool log) ++ u32 mpls_label_count, bool log, ++ u32 depth) + { + const struct nlattr *attrs[OVS_DEC_TTL_ATTR_MAX + 1]; + int start, action_start, err, rem; +@@ -2660,7 +2665,8 @@ static int validate_and_copy_dec_ttl(struct net *net, + return action_start; + + err = __ovs_nla_copy_actions(net, actions, key, sfa, eth_type, +- vlan_tci, mpls_label_count, log); ++ vlan_tci, mpls_label_count, log, ++ depth + 1); + if (err) + return err; + +@@ -2674,7 +2680,8 @@ static int validate_and_copy_clone(struct net *net, + const struct sw_flow_key *key, + struct sw_flow_actions **sfa, + __be16 eth_type, __be16 vlan_tci, +- u32 mpls_label_count, bool log, bool last) ++ u32 mpls_label_count, bool log, bool last, ++ u32 depth) + { + int start, err; + u32 exec; +@@ -2694,7 +2701,8 @@ static int validate_and_copy_clone(struct net *net, + return err; + + err = __ovs_nla_copy_actions(net, attr, key, sfa, +- eth_type, vlan_tci, mpls_label_count, log); ++ eth_type, vlan_tci, mpls_label_count, log, ++ depth + 1); + if (err) + return err; + +@@ -3063,7 +3071,7 @@ static int validate_and_copy_check_pkt_len(struct net *net, + struct sw_flow_actions **sfa, + __be16 eth_type, __be16 vlan_tci, + u32 mpls_label_count, +- bool log, bool last) ++ bool log, bool last, u32 depth) + { + const struct nlattr *acts_if_greater, *acts_if_lesser_eq; + struct nlattr *a[OVS_CHECK_PKT_LEN_ATTR_MAX + 1]; +@@ -3111,7 +3119,8 @@ static int validate_and_copy_check_pkt_len(struct net *net, + return nested_acts_start; + + err = __ovs_nla_copy_actions(net, acts_if_lesser_eq, key, sfa, +- eth_type, vlan_tci, mpls_label_count, log); ++ eth_type, vlan_tci, mpls_label_count, log, ++ depth + 1); + + if (err) + return err; +@@ -3124,7 +3133,8 @@ static int validate_and_copy_check_pkt_len(struct net *net, + return nested_acts_start; + + err = __ovs_nla_copy_actions(net, acts_if_greater, key, sfa, +- eth_type, vlan_tci, mpls_label_count, log); ++ eth_type, vlan_tci, mpls_label_count, log, ++ depth + 1); + + if (err) + return err; +@@ -3152,12 +3162,16 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr, + const struct sw_flow_key *key, + struct sw_flow_actions **sfa, + __be16 eth_type, __be16 vlan_tci, +- u32 mpls_label_count, bool log) ++ u32 mpls_label_count, bool log, ++ u32 depth) + { + u8 mac_proto = ovs_key_mac_proto(key); + const struct nlattr *a; + int rem, err; + ++ if (depth > OVS_COPY_ACTIONS_MAX_DEPTH) ++ return -EOVERFLOW; ++ + nla_for_each_nested(a, attr, rem) { + /* Expected argument lengths, (u32)-1 for variable length. */ + static const u32 action_lens[OVS_ACTION_ATTR_MAX + 1] = { +@@ -3355,7 +3369,7 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr, + err = validate_and_copy_sample(net, a, key, sfa, + eth_type, vlan_tci, + mpls_label_count, +- log, last); ++ log, last, depth); + if (err) + return err; + skip_copy = true; +@@ -3426,7 +3440,7 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr, + err = validate_and_copy_clone(net, a, key, sfa, + eth_type, vlan_tci, + mpls_label_count, +- log, last); ++ log, last, depth); + if (err) + return err; + skip_copy = true; +@@ -3440,7 +3454,8 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr, + eth_type, + vlan_tci, + mpls_label_count, +- log, last); ++ log, last, ++ depth); + if (err) + return err; + skip_copy = true; +@@ -3450,7 +3465,8 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr, + case OVS_ACTION_ATTR_DEC_TTL: + err = validate_and_copy_dec_ttl(net, a, key, sfa, + eth_type, vlan_tci, +- mpls_label_count, log); ++ mpls_label_count, log, ++ depth); + if (err) + return err; + skip_copy = true; +@@ -3495,7 +3511,8 @@ int ovs_nla_copy_actions(struct net *net, const struct nlattr *attr, + + (*sfa)->orig_len = nla_len(attr); + err = __ovs_nla_copy_actions(net, attr, key, sfa, key->eth.type, +- key->eth.vlan.tci, mpls_label_count, log); ++ key->eth.vlan.tci, mpls_label_count, log, ++ 0); + if (err) + ovs_nla_free_flow_actions(*sfa); + diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index cb6406f485a9..71e1f15d9dce 100644 --- a/scripts/mod/modpost.c @@ -1606,3 +2090,176 @@ index b53753dee02f..90701fc65aa2 100644 PACKAGE = cpupower PACKAGE_BUGREPORT = linux-pm@vger.kernel.org +diff --git a/tools/testing/selftests/net/openvswitch/openvswitch.sh b/tools/testing/selftests/net/openvswitch/openvswitch.sh +index f8499d4c87f3..36e40256ab92 100755 +--- a/tools/testing/selftests/net/openvswitch/openvswitch.sh ++++ b/tools/testing/selftests/net/openvswitch/openvswitch.sh +@@ -502,7 +502,20 @@ test_netlink_checks () { + wc -l) == 2 ] || \ + return 1 + ++ info "Checking clone depth" + ERR_MSG="Flow actions may not be safe on all matching packets" ++ PRE_TEST=$(dmesg | grep -c "${ERR_MSG}") ++ ovs_add_flow "test_netlink_checks" nv0 \ ++ 'in_port(1),eth(),eth_type(0x800),ipv4()' \ ++ 'clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(drop)))))))))))))))))' \ ++ >/dev/null 2>&1 && return 1 ++ POST_TEST=$(dmesg | grep -c "${ERR_MSG}") ++ ++ if [ "$PRE_TEST" == "$POST_TEST" ]; then ++ info "failed - clone depth too large" ++ return 1 ++ fi ++ + PRE_TEST=$(dmesg | grep -c "${ERR_MSG}") + ovs_add_flow "test_netlink_checks" nv0 \ + 'in_port(1),eth(),eth_type(0x0806),arp()' 'drop(0),2' \ +diff --git a/tools/testing/selftests/net/openvswitch/ovs-dpctl.py b/tools/testing/selftests/net/openvswitch/ovs-dpctl.py +index b97e621face9..5e0e539a323d 100644 +--- a/tools/testing/selftests/net/openvswitch/ovs-dpctl.py ++++ b/tools/testing/selftests/net/openvswitch/ovs-dpctl.py +@@ -299,7 +299,7 @@ class ovsactions(nla): + ("OVS_ACTION_ATTR_PUSH_NSH", "none"), + ("OVS_ACTION_ATTR_POP_NSH", "flag"), + ("OVS_ACTION_ATTR_METER", "none"), +- ("OVS_ACTION_ATTR_CLONE", "none"), ++ ("OVS_ACTION_ATTR_CLONE", "recursive"), + ("OVS_ACTION_ATTR_CHECK_PKT_LEN", "none"), + ("OVS_ACTION_ATTR_ADD_MPLS", "none"), + ("OVS_ACTION_ATTR_DEC_TTL", "none"), +@@ -465,29 +465,42 @@ class ovsactions(nla): + print_str += "pop_mpls" + else: + datum = self.get_attr(field[0]) +- print_str += datum.dpstr(more) ++ if field[0] == "OVS_ACTION_ATTR_CLONE": ++ print_str += "clone(" ++ print_str += datum.dpstr(more) ++ print_str += ")" ++ else: ++ print_str += datum.dpstr(more) + + return print_str + + def parse(self, actstr): ++ totallen = len(actstr) + while len(actstr) != 0: + parsed = False ++ parencount = 0 + if actstr.startswith("drop"): + # If no reason is provided, the implicit drop is used (i.e no + # action). If some reason is given, an explicit action is used. +- actstr, reason = parse_extract_field( +- actstr, +- "drop(", +- "([0-9]+)", +- lambda x: int(x, 0), +- False, +- None, +- ) ++ reason = None ++ if actstr.startswith("drop("): ++ parencount += 1 ++ ++ actstr, reason = parse_extract_field( ++ actstr, ++ "drop(", ++ "([0-9]+)", ++ lambda x: int(x, 0), ++ False, ++ None, ++ ) ++ + if reason is not None: + self["attrs"].append(["OVS_ACTION_ATTR_DROP", reason]) + parsed = True + else: +- return ++ actstr = actstr[len("drop"): ] ++ return (totallen - len(actstr)) + + elif parse_starts_block(actstr, "^(\d+)", False, True): + actstr, output = parse_extract_field( +@@ -504,6 +517,7 @@ class ovsactions(nla): + False, + 0, + ) ++ parencount += 1 + self["attrs"].append(["OVS_ACTION_ATTR_RECIRC", recircid]) + parsed = True + +@@ -516,12 +530,22 @@ class ovsactions(nla): + + for flat_act in parse_flat_map: + if parse_starts_block(actstr, flat_act[0], False): +- actstr += len(flat_act[0]) ++ actstr = actstr[len(flat_act[0]):] + self["attrs"].append([flat_act[1]]) + actstr = actstr[strspn(actstr, ", ") :] + parsed = True + +- if parse_starts_block(actstr, "ct(", False): ++ if parse_starts_block(actstr, "clone(", False): ++ parencount += 1 ++ subacts = ovsactions() ++ actstr = actstr[len("clone("):] ++ parsedLen = subacts.parse(actstr) ++ lst = [] ++ self["attrs"].append(("OVS_ACTION_ATTR_CLONE", subacts)) ++ actstr = actstr[parsedLen:] ++ parsed = True ++ elif parse_starts_block(actstr, "ct(", False): ++ parencount += 1 + actstr = actstr[len("ct(") :] + ctact = ovsactions.ctact() + +@@ -553,6 +577,7 @@ class ovsactions(nla): + natact = ovsactions.ctact.natattr() + + if actstr.startswith("("): ++ parencount += 1 + t = None + actstr = actstr[1:] + if actstr.startswith("src"): +@@ -607,15 +632,29 @@ class ovsactions(nla): + actstr = actstr[strspn(actstr, ", ") :] + + ctact["attrs"].append(["OVS_CT_ATTR_NAT", natact]) +- actstr = actstr[strspn(actstr, ",) ") :] ++ actstr = actstr[strspn(actstr, ", ") :] + + self["attrs"].append(["OVS_ACTION_ATTR_CT", ctact]) + parsed = True + +- actstr = actstr[strspn(actstr, "), ") :] ++ actstr = actstr[strspn(actstr, ", ") :] ++ while parencount > 0: ++ parencount -= 1 ++ actstr = actstr[strspn(actstr, " "):] ++ if len(actstr) and actstr[0] != ")": ++ raise ValueError("Action str: '%s' unbalanced" % actstr) ++ actstr = actstr[1:] ++ ++ if len(actstr) and actstr[0] == ")": ++ return (totallen - len(actstr)) ++ ++ actstr = actstr[strspn(actstr, ", ") :] ++ + if not parsed: + raise ValueError("Action str: '%s' not supported" % actstr) + ++ return (totallen - len(actstr)) ++ + + class ovskey(nla): + nla_flags = NLA_F_NESTED +@@ -2111,6 +2150,8 @@ def main(argv): + ovsflow = OvsFlow() + ndb = NDB() + ++ sys.setrecursionlimit(100000) ++ + if hasattr(args, "showdp"): + found = False + for iface in ndb.interfaces: |