From 4c4ddb2cb6df13013e74e4341fe6c42140da811c Mon Sep 17 00:00:00 2001 From: almalinux-bot-kernel Date: Sat, 1 Aug 2026 05:18:39 +0000 Subject: [PATCH] Import of kernel-6.12.0-211.39.1.el10_2 --- ....38.1.el10 => COPYING-6.12.0-211.39.1.el10 | 0 Makefile.rhelver | 2 +- drivers/md/dm-log.c | 6 +- drivers/net/can/vxcan.c | 22 +-- drivers/net/ethernet/google/gve/gve.h | 18 +-- drivers/net/ethernet/google/gve/gve_adminq.c | 18 +-- drivers/net/ethernet/google/gve/gve_main.c | 41 +++++ drivers/net/ethernet/google/gve/gve_rx.c | 5 +- drivers/net/ethernet/google/gve/gve_rx_dqo.c | 9 +- drivers/net/ethernet/google/gve/gve_tx.c | 5 +- drivers/net/ethernet/google/gve/gve_tx_dqo.c | 5 +- drivers/net/netkit.c | 22 +-- drivers/net/veth.c | 30 +--- drivers/scsi/scsi_error.c | 11 +- drivers/scsi/scsi_lib.c | 8 + fs/notify/fdinfo.c | 12 +- fs/overlayfs/copy_up.c | 5 +- include/net/rtnetlink.h | 3 + kernel.sbat | 2 +- kernel/fork.c | 12 +- net/core/rtnetlink.c | 145 ++++++++++++++---- net/ipv6/rpl_iptunnel.c | 10 ++ net/ipv6/seg6_iptunnel.c | 9 ++ redhat/kernel.changelog-10.2 | 16 ++ uki-addons.sbat | 2 +- uki.sbat | 2 +- 26 files changed, 271 insertions(+), 149 deletions(-) rename COPYING-6.12.0-211.38.1.el10 => COPYING-6.12.0-211.39.1.el10 (100%) diff --git a/COPYING-6.12.0-211.38.1.el10 b/COPYING-6.12.0-211.39.1.el10 similarity index 100% rename from COPYING-6.12.0-211.38.1.el10 rename to COPYING-6.12.0-211.39.1.el10 diff --git a/Makefile.rhelver b/Makefile.rhelver index 470568593e..028e2bbe0b 100644 --- a/Makefile.rhelver +++ b/Makefile.rhelver @@ -12,7 +12,7 @@ RHEL_MINOR = 2 # # Use this spot to avoid future merge conflicts. # Do not trim this comment. -RHEL_RELEASE = 211.38.1 +RHEL_RELEASE = 211.39.1 # # RHEL_REBASE_NUM diff --git a/drivers/md/dm-log.c b/drivers/md/dm-log.c index 9d85d045f9..d37468cdaa 100644 --- a/drivers/md/dm-log.c +++ b/drivers/md/dm-log.c @@ -373,7 +373,7 @@ static int create_log_context(struct dm_dirty_log *log, struct dm_target *ti, struct log_c *lc; uint32_t region_size; - unsigned int region_count; + sector_t region_count; size_t bitset_size, buf_size; int r; char dummy; @@ -401,6 +401,10 @@ static int create_log_context(struct dm_dirty_log *log, struct dm_target *ti, } region_count = dm_sector_div_up(ti->len, region_size); + if (region_count > UINT_MAX) { + DMWARN("region count exceeds limit of %u", UINT_MAX); + return -EINVAL; + } lc = kmalloc(sizeof(*lc), GFP_KERNEL); if (!lc) { diff --git a/drivers/net/can/vxcan.c b/drivers/net/can/vxcan.c index 9e1b7d4100..ca88119410 100644 --- a/drivers/net/can/vxcan.c +++ b/drivers/net/can/vxcan.c @@ -172,13 +172,12 @@ static void vxcan_setup(struct net_device *dev) /* forward declaration for rtnl_create_link() */ static struct rtnl_link_ops vxcan_link_ops; -static int vxcan_newlink(struct net *net, struct net_device *dev, +static int vxcan_newlink(struct net *peer_net, struct net_device *dev, struct nlattr *tb[], struct nlattr *data[], struct netlink_ext_ack *extack) { struct vxcan_priv *priv; struct net_device *peer; - struct net *peer_net; struct nlattr *peer_tb[IFLA_MAX + 1], **tbp = tb; char ifname[IFNAMSIZ]; @@ -188,14 +187,10 @@ static int vxcan_newlink(struct net *net, struct net_device *dev, /* register peer device */ if (data && data[VXCAN_INFO_PEER]) { - struct nlattr *nla_peer; + struct nlattr *nla_peer = data[VXCAN_INFO_PEER]; - nla_peer = data[VXCAN_INFO_PEER]; ifmp = nla_data(nla_peer); - err = rtnl_nla_parse_ifinfomsg(peer_tb, nla_peer, extack); - if (err < 0) - return err; - + rtnl_nla_parse_ifinfomsg(peer_tb, nla_peer, extack); tbp = peer_tb; } @@ -207,23 +202,15 @@ static int vxcan_newlink(struct net *net, struct net_device *dev, name_assign_type = NET_NAME_ENUM; } - peer_net = rtnl_link_get_net(net, tbp); - if (IS_ERR(peer_net)) - return PTR_ERR(peer_net); - peer = rtnl_create_link(peer_net, ifname, name_assign_type, &vxcan_link_ops, tbp, extack); - if (IS_ERR(peer)) { - put_net(peer_net); + if (IS_ERR(peer)) return PTR_ERR(peer); - } if (ifmp && dev->ifindex) peer->ifindex = ifmp->ifi_index; err = register_netdevice(peer); - put_net(peer_net); - peer_net = NULL; if (err < 0) { free_netdev(peer); return err; @@ -302,6 +289,7 @@ static struct rtnl_link_ops vxcan_link_ops = { .newlink = vxcan_newlink, .dellink = vxcan_dellink, .policy = vxcan_policy, + .peer_type = VXCAN_INFO_PEER, .maxtype = VXCAN_INFO_MAX, .get_link_net = vxcan_get_link_net, }; diff --git a/drivers/net/ethernet/google/gve/gve.h b/drivers/net/ethernet/google/gve/gve.h index adc2b9a3d9..65bd511a73 100644 --- a/drivers/net/ethernet/google/gve/gve.h +++ b/drivers/net/ethernet/google/gve/gve.h @@ -71,8 +71,6 @@ #define GVE_DEFAULT_HEADER_BUFFER_SIZE 128 -#define DQO_QPL_DEFAULT_TX_PAGES 512 - /* Maximum TSO size supported on DQO */ #define GVE_DQO_TX_MAX 0x3FFFF @@ -646,6 +644,7 @@ struct gve_ptype_lut { /* Parameters for allocating resources for tx queues */ struct gve_tx_alloc_rings_cfg { struct gve_queue_config *qcfg; + u16 pages_per_qpl; u16 ring_size; u16 start_idx; @@ -661,6 +660,7 @@ struct gve_rx_alloc_rings_cfg { /* tx config is also needed to determine QPL ids */ struct gve_queue_config *qcfg; struct gve_queue_config *qcfg_tx; + u16 pages_per_qpl; u16 ring_size; u16 packet_buffer_size; @@ -738,7 +738,8 @@ struct gve_priv { u16 min_rx_desc_cnt; bool modify_ring_size_enabled; bool default_min_ring_size; - u16 tx_pages_per_qpl; /* Suggested number of pages per qpl for TX queues by NIC */ + u16 tx_pages_per_qpl; + u16 rx_pages_per_qpl; u64 max_registered_pages; u64 num_registered_pages; /* num pages registered with NIC */ struct bpf_prog *xdp_prog; /* XDP BPF program */ @@ -1071,14 +1072,6 @@ static inline u32 gve_rx_start_qpl_id(const struct gve_queue_config *tx_cfg) return gve_get_rx_qpl_id(tx_cfg, 0); } -static inline u32 gve_get_rx_pages_per_qpl_dqo(u32 rx_desc_cnt) -{ - /* For DQO, page count should be more than ring size for - * out-of-order completions. Set it to two times of ring size. - */ - return 2 * rx_desc_cnt; -} - /* Returns the correct dma direction for tx and rx qpls */ static inline enum dma_data_direction gve_qpl_dma_dir(struct gve_priv *priv, int id) @@ -1178,6 +1171,9 @@ int gve_reset(struct gve_priv *priv, bool attempt_teardown); void gve_get_curr_alloc_cfgs(struct gve_priv *priv, struct gve_tx_alloc_rings_cfg *tx_alloc_cfg, struct gve_rx_alloc_rings_cfg *rx_alloc_cfg); +void gve_update_num_qpl_pages(struct gve_priv *priv, + struct gve_rx_alloc_rings_cfg *rx_alloc_cfg, + struct gve_tx_alloc_rings_cfg *tx_alloc_cfg); int gve_adjust_config(struct gve_priv *priv, struct gve_tx_alloc_rings_cfg *tx_alloc_cfg, struct gve_rx_alloc_rings_cfg *rx_alloc_cfg); diff --git a/drivers/net/ethernet/google/gve/gve_adminq.c b/drivers/net/ethernet/google/gve/gve_adminq.c index e44e8b1396..4f18e143f0 100644 --- a/drivers/net/ethernet/google/gve/gve_adminq.c +++ b/drivers/net/ethernet/google/gve/gve_adminq.c @@ -911,14 +911,6 @@ static void gve_enable_supported_features(struct gve_priv *priv, priv->dev->max_mtu = be16_to_cpu(dev_op_jumbo_frames->max_mtu); } - /* Override pages for qpl for DQO-QPL */ - if (dev_op_dqo_qpl) { - priv->tx_pages_per_qpl = - be16_to_cpu(dev_op_dqo_qpl->tx_pages_per_qpl); - if (priv->tx_pages_per_qpl == 0) - priv->tx_pages_per_qpl = DQO_QPL_DEFAULT_TX_PAGES; - } - if (dev_op_buffer_sizes && (supported_features_mask & GVE_SUP_BUFFER_SIZES_MASK)) { priv->max_rx_buffer_size = @@ -934,12 +926,10 @@ static void gve_enable_supported_features(struct gve_priv *priv, if (dev_op_modify_ring && (supported_features_mask & GVE_SUP_MODIFY_RING_MASK)) { priv->modify_ring_size_enabled = true; - - /* max ring size for DQO QPL should not be overwritten because of device limit */ - if (priv->queue_format != GVE_DQO_QPL_FORMAT) { - priv->max_rx_desc_cnt = be16_to_cpu(dev_op_modify_ring->max_rx_ring_size); - priv->max_tx_desc_cnt = be16_to_cpu(dev_op_modify_ring->max_tx_ring_size); - } + priv->max_rx_desc_cnt = + be16_to_cpu(dev_op_modify_ring->max_rx_ring_size); + priv->max_tx_desc_cnt = + be16_to_cpu(dev_op_modify_ring->max_tx_ring_size); if (priv->default_min_ring_size) { /* If device hasn't provided minimums, use default minimums */ priv->min_tx_desc_cnt = GVE_DEFAULT_MIN_TX_RING_SIZE; diff --git a/drivers/net/ethernet/google/gve/gve_main.c b/drivers/net/ethernet/google/gve/gve_main.c index 72e9ce97cc..a065891ff0 100644 --- a/drivers/net/ethernet/google/gve/gve_main.c +++ b/drivers/net/ethernet/google/gve/gve_main.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -926,6 +927,7 @@ static void gve_tx_get_curr_alloc_cfg(struct gve_priv *priv, cfg->qcfg = &priv->tx_cfg; cfg->raw_addressing = !gve_is_qpl(priv); cfg->ring_size = priv->tx_desc_cnt; + cfg->pages_per_qpl = priv->tx_pages_per_qpl; cfg->start_idx = 0; cfg->num_rings = gve_num_tx_queues(priv); cfg->tx = priv->tx; @@ -981,12 +983,48 @@ static int gve_alloc_xdp_rings(struct gve_priv *priv) return 0; } +void gve_update_num_qpl_pages(struct gve_priv *priv, + struct gve_rx_alloc_rings_cfg *rx_alloc_cfg, + struct gve_tx_alloc_rings_cfg *tx_alloc_cfg) +{ + u64 ideal_tx_pages, ideal_rx_pages; + u16 tx_num_queues, rx_num_queues; + u64 max_pages, tx_pages; + + if (priv->queue_format == GVE_GQI_QPL_FORMAT) { + rx_alloc_cfg->pages_per_qpl = rx_alloc_cfg->ring_size; + } else if (priv->queue_format == GVE_DQO_QPL_FORMAT) { + /* + * We want 2 pages per RX descriptor and half a page per TX + * descriptor, which means the fraction ideal_tx_pages / + * (ideal_tx_pages + ideal_rx_pages) of the pages we allocate + * should be for TX. Shrink proportionally as necessary to avoid + * allocating more than max_registered_pages total pages. + */ + tx_num_queues = tx_alloc_cfg->qcfg->num_queues; + rx_num_queues = rx_alloc_cfg->qcfg->num_queues; + + ideal_tx_pages = tx_alloc_cfg->ring_size * tx_num_queues / 2; + ideal_rx_pages = rx_alloc_cfg->ring_size * rx_num_queues * 2; + max_pages = min(priv->max_registered_pages, + ideal_tx_pages + ideal_rx_pages); + + tx_pages = div64_u64(max_pages * ideal_tx_pages, + ideal_tx_pages + ideal_rx_pages); + tx_alloc_cfg->pages_per_qpl = div_u64(tx_pages, tx_num_queues); + rx_alloc_cfg->pages_per_qpl = div_u64(max_pages - tx_pages, + rx_num_queues); + } +} + static int gve_queues_mem_alloc(struct gve_priv *priv, struct gve_tx_alloc_rings_cfg *tx_alloc_cfg, struct gve_rx_alloc_rings_cfg *rx_alloc_cfg) { int err; + gve_update_num_qpl_pages(priv, rx_alloc_cfg, tx_alloc_cfg); + if (gve_is_gqi(priv)) err = gve_tx_alloc_rings_gqi(priv, tx_alloc_cfg); else @@ -1281,6 +1319,7 @@ static void gve_rx_get_curr_alloc_cfg(struct gve_priv *priv, cfg->raw_addressing = !gve_is_qpl(priv); cfg->enable_header_split = priv->header_split_enabled; cfg->ring_size = priv->rx_desc_cnt; + cfg->pages_per_qpl = priv->rx_pages_per_qpl; cfg->packet_buffer_size = gve_is_gqi(priv) ? GVE_DEFAULT_RX_BUFFER_SIZE : priv->data_buffer_size_dqo; @@ -1360,6 +1399,8 @@ static int gve_queues_start(struct gve_priv *priv, priv->rx_cfg = *rx_alloc_cfg->qcfg; priv->tx_desc_cnt = tx_alloc_cfg->ring_size; priv->rx_desc_cnt = rx_alloc_cfg->ring_size; + priv->tx_pages_per_qpl = tx_alloc_cfg->pages_per_qpl; + priv->rx_pages_per_qpl = rx_alloc_cfg->pages_per_qpl; if (priv->xdp_prog) priv->num_xdp_queues = priv->rx_cfg.num_queues; diff --git a/drivers/net/ethernet/google/gve/gve_rx.c b/drivers/net/ethernet/google/gve/gve_rx.c index acb73d4d0d..77077caa02 100644 --- a/drivers/net/ethernet/google/gve/gve_rx.c +++ b/drivers/net/ethernet/google/gve/gve_rx.c @@ -272,7 +272,6 @@ int gve_rx_alloc_ring_gqi(struct gve_priv *priv, struct device *hdev = &priv->pdev->dev; u32 slots = cfg->ring_size; int filled_pages; - int qpl_page_cnt; u32 qpl_id = 0; size_t bytes; int err; @@ -308,10 +307,8 @@ int gve_rx_alloc_ring_gqi(struct gve_priv *priv, if (!rx->data.raw_addressing) { qpl_id = gve_get_rx_qpl_id(cfg->qcfg_tx, rx->q_num); - qpl_page_cnt = cfg->ring_size; - rx->data.qpl = gve_alloc_queue_page_list(priv, qpl_id, - qpl_page_cnt); + cfg->pages_per_qpl); if (!rx->data.qpl) { err = -ENOMEM; goto abort_with_copy_pool; diff --git a/drivers/net/ethernet/google/gve/gve_rx_dqo.c b/drivers/net/ethernet/google/gve/gve_rx_dqo.c index 1154c1d8f6..1cbaf23626 100644 --- a/drivers/net/ethernet/google/gve/gve_rx_dqo.c +++ b/drivers/net/ethernet/google/gve/gve_rx_dqo.c @@ -178,7 +178,7 @@ static int gve_alloc_page_dqo(struct gve_rx_ring *rx, return err; } else { idx = rx->dqo.next_qpl_page_idx; - if (idx >= gve_get_rx_pages_per_qpl_dqo(priv->rx_desc_cnt)) { + if (idx >= priv->rx_pages_per_qpl) { net_err_ratelimited("%s: Out of QPL pages\n", priv->dev->name); return -ENOMEM; @@ -382,7 +382,6 @@ int gve_rx_alloc_ring_dqo(struct gve_priv *priv, int idx) { struct device *hdev = &priv->pdev->dev; - int qpl_page_cnt; size_t size; u32 qpl_id; @@ -397,7 +396,7 @@ int gve_rx_alloc_ring_dqo(struct gve_priv *priv, rx->dqo.num_buf_states = cfg->raw_addressing ? min_t(s16, S16_MAX, buffer_queue_slots * 4) : - gve_get_rx_pages_per_qpl_dqo(cfg->ring_size); + cfg->pages_per_qpl; rx->dqo.buf_states = kvcalloc(rx->dqo.num_buf_states, sizeof(rx->dqo.buf_states[0]), GFP_KERNEL); @@ -426,10 +425,8 @@ int gve_rx_alloc_ring_dqo(struct gve_priv *priv, if (!cfg->raw_addressing) { qpl_id = gve_get_rx_qpl_id(cfg->qcfg_tx, rx->q_num); - qpl_page_cnt = gve_get_rx_pages_per_qpl_dqo(cfg->ring_size); - rx->dqo.qpl = gve_alloc_queue_page_list(priv, qpl_id, - qpl_page_cnt); + cfg->pages_per_qpl); if (!rx->dqo.qpl) goto err; rx->dqo.next_qpl_page_idx = 0; diff --git a/drivers/net/ethernet/google/gve/gve_tx.c b/drivers/net/ethernet/google/gve/gve_tx.c index e7fb7d6d28..d471507ff9 100644 --- a/drivers/net/ethernet/google/gve/gve_tx.c +++ b/drivers/net/ethernet/google/gve/gve_tx.c @@ -261,7 +261,6 @@ static int gve_tx_alloc_ring_gqi(struct gve_priv *priv, int idx) { struct device *hdev = &priv->pdev->dev; - int qpl_page_cnt; u32 qpl_id = 0; size_t bytes; @@ -288,10 +287,8 @@ static int gve_tx_alloc_ring_gqi(struct gve_priv *priv, tx->dev = hdev; if (!tx->raw_addressing) { qpl_id = gve_tx_qpl_id(priv, tx->q_num); - qpl_page_cnt = priv->tx_pages_per_qpl; - tx->tx_fifo.qpl = gve_alloc_queue_page_list(priv, qpl_id, - qpl_page_cnt); + cfg->pages_per_qpl); if (!tx->tx_fifo.qpl) goto abort_with_desc; diff --git a/drivers/net/ethernet/google/gve/gve_tx_dqo.c b/drivers/net/ethernet/google/gve/gve_tx_dqo.c index f879426cb5..9118256128 100644 --- a/drivers/net/ethernet/google/gve/gve_tx_dqo.c +++ b/drivers/net/ethernet/google/gve/gve_tx_dqo.c @@ -287,7 +287,6 @@ static int gve_tx_alloc_ring_dqo(struct gve_priv *priv, { struct device *hdev = &priv->pdev->dev; int num_pending_packets; - int qpl_page_cnt; size_t bytes; u32 qpl_id; int i; @@ -357,10 +356,8 @@ static int gve_tx_alloc_ring_dqo(struct gve_priv *priv, if (!cfg->raw_addressing) { qpl_id = gve_tx_qpl_id(priv, tx->q_num); - qpl_page_cnt = priv->tx_pages_per_qpl; - tx->dqo.qpl = gve_alloc_queue_page_list(priv, qpl_id, - qpl_page_cnt); + cfg->pages_per_qpl); if (!tx->dqo.qpl) goto err; diff --git a/drivers/net/netkit.c b/drivers/net/netkit.c index a909fdc035..3261760f02 100644 --- a/drivers/net/netkit.c +++ b/drivers/net/netkit.c @@ -326,7 +326,7 @@ static int netkit_validate(struct nlattr *tb[], struct nlattr *data[], static struct rtnl_link_ops netkit_link_ops; -static int netkit_new_link(struct net *src_net, struct net_device *dev, +static int netkit_new_link(struct net *peer_net, struct net_device *dev, struct nlattr *tb[], struct nlattr *data[], struct netlink_ext_ack *extack) { @@ -339,7 +339,6 @@ static int netkit_new_link(struct net *src_net, struct net_device *dev, struct net_device *peer; char ifname[IFNAMSIZ]; struct netkit *nk; - struct net *net; int err; if (data) { @@ -353,12 +352,7 @@ static int netkit_new_link(struct net *src_net, struct net_device *dev, if (data[IFLA_NETKIT_PEER_INFO]) { attr = data[IFLA_NETKIT_PEER_INFO]; ifmp = nla_data(attr); - err = rtnl_nla_parse_ifinfomsg(peer_tb, attr, extack); - if (err < 0) - return err; - err = netkit_validate(peer_tb, NULL, extack); - if (err < 0) - return err; + rtnl_nla_parse_ifinfomsg(peer_tb, attr, extack); tbp = peer_tb; } if (data[IFLA_NETKIT_POLICY]) { @@ -388,16 +382,10 @@ static int netkit_new_link(struct net *src_net, struct net_device *dev, (tb[IFLA_ADDRESS] || tbp[IFLA_ADDRESS])) return -EOPNOTSUPP; - net = rtnl_link_get_net(src_net, tbp); - if (IS_ERR(net)) - return PTR_ERR(net); - - peer = rtnl_create_link(net, ifname, ifname_assign_type, + peer = rtnl_create_link(peer_net, ifname, ifname_assign_type, &netkit_link_ops, tbp, extack); - if (IS_ERR(peer)) { - put_net(net); + if (IS_ERR(peer)) return PTR_ERR(peer); - } netif_inherit_tso_max(peer, dev); @@ -413,7 +401,6 @@ static int netkit_new_link(struct net *src_net, struct net_device *dev, bpf_mprog_bundle_init(&nk->bundle); err = register_netdevice(peer); - put_net(net); if (err < 0) goto err_register_peer; netif_carrier_off(peer); @@ -953,6 +940,7 @@ static struct rtnl_link_ops netkit_link_ops = { .fill_info = netkit_fill_info, .policy = netkit_policy, .validate = netkit_validate, + .peer_type = IFLA_NETKIT_PEER_INFO, .maxtype = IFLA_NETKIT_MAX, }; diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 7883a18ceb..de645eee29 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -1766,7 +1766,7 @@ static int veth_init_queues(struct net_device *dev, struct nlattr *tb[]) return 0; } -static int veth_newlink(struct net *src_net, struct net_device *dev, +static int veth_newlink(struct net *peer_net, struct net_device *dev, struct nlattr *tb[], struct nlattr *data[], struct netlink_ext_ack *extack) { @@ -1777,24 +1777,15 @@ static int veth_newlink(struct net *src_net, struct net_device *dev, struct nlattr *peer_tb[IFLA_MAX + 1], **tbp; unsigned char name_assign_type; struct ifinfomsg *ifmp; - struct net *net; /* * create and register peer first */ - if (data != NULL && data[VETH_INFO_PEER] != NULL) { - struct nlattr *nla_peer; + if (data && data[VETH_INFO_PEER]) { + struct nlattr *nla_peer = data[VETH_INFO_PEER]; - nla_peer = data[VETH_INFO_PEER]; ifmp = nla_data(nla_peer); - err = rtnl_nla_parse_ifinfomsg(peer_tb, nla_peer, extack); - if (err < 0) - return err; - - err = veth_validate(peer_tb, NULL, extack); - if (err < 0) - return err; - + rtnl_nla_parse_ifinfomsg(peer_tb, nla_peer, extack); tbp = peer_tb; } else { ifmp = NULL; @@ -1809,16 +1800,10 @@ static int veth_newlink(struct net *src_net, struct net_device *dev, name_assign_type = NET_NAME_ENUM; } - net = rtnl_link_get_net(src_net, tbp); - if (IS_ERR(net)) - return PTR_ERR(net); - - peer = rtnl_create_link(net, ifname, name_assign_type, + peer = rtnl_create_link(peer_net, ifname, name_assign_type, &veth_link_ops, tbp, extack); - if (IS_ERR(peer)) { - put_net(net); + if (IS_ERR(peer)) return PTR_ERR(peer); - } if (!ifmp || !tbp[IFLA_ADDRESS]) eth_hw_addr_random(peer); @@ -1829,8 +1814,6 @@ static int veth_newlink(struct net *src_net, struct net_device *dev, netif_inherit_tso_max(peer, dev); err = register_netdevice(peer); - put_net(net); - net = NULL; if (err < 0) goto err_register_peer; @@ -1953,6 +1936,7 @@ static struct rtnl_link_ops veth_link_ops = { .newlink = veth_newlink, .dellink = veth_dellink, .policy = veth_policy, + .peer_type = VETH_INFO_PEER, .maxtype = VETH_INFO_MAX, .get_link_net = veth_get_link_net, .get_num_tx_queues = veth_get_num_queues, diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 1c13812a3f..9094e98daa 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -282,11 +282,20 @@ static void scsi_eh_inc_host_failed(struct rcu_head *head) { struct scsi_cmnd *scmd = container_of(head, typeof(*scmd), rcu); struct Scsi_Host *shost = scmd->device->host; - unsigned int busy = scsi_host_busy(shost); + unsigned int busy; unsigned long flags; spin_lock_irqsave(shost->host_lock, flags); shost->host_failed++; + spin_unlock_irqrestore(shost->host_lock, flags); + /* + * The counting of busy requests needs to occur after adding to + * host_failed or after the lock acquire for adding to host_failed + * to prevent a race with host unbusy and missing an eh wakeup. + */ + busy = scsi_host_busy(shost); + + spin_lock_irqsave(shost->host_lock, flags); scsi_eh_wakeup(shost, busy); spin_unlock_irqrestore(shost->host_lock, flags); } diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 0c65ecfedf..373fc423bb 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -376,6 +376,14 @@ static void scsi_dec_host_busy(struct Scsi_Host *shost, struct scsi_cmnd *cmd) rcu_read_lock(); __clear_bit(SCMD_STATE_INFLIGHT, &cmd->state); if (unlikely(scsi_host_in_recovery(shost))) { + /* + * Ensure the clear of SCMD_STATE_INFLIGHT is visible to + * other CPUs before counting busy requests. Otherwise, + * reordering can cause CPUs to race and miss an eh wakeup + * when no CPU sees all busy requests as done or timed out. + */ + smp_mb(); + unsigned int busy = scsi_host_busy(shost); spin_lock_irqsave(shost->host_lock, flags); diff --git a/fs/notify/fdinfo.c b/fs/notify/fdinfo.c index dec5530340..d2aa8985c0 100644 --- a/fs/notify/fdinfo.c +++ b/fs/notify/fdinfo.c @@ -17,6 +17,7 @@ #include "fanotify/fanotify.h" #include "fdinfo.h" #include "fsnotify.h" +#include "../internal.h" #if defined(CONFIG_PROC_FS) @@ -46,11 +47,14 @@ static void show_mark_fhandle(struct seq_file *m, struct inode *inode) size = f->handle_bytes >> 2; - ret = exportfs_encode_fid(inode, (struct fid *)f->f_handle, &size); - if ((ret == FILEID_INVALID) || (ret < 0)) { - WARN_ONCE(1, "Can't encode file handler for inotify: %d\n", ret); + if (!super_trylock_shared(inode->i_sb)) + return; + + ret = exportfs_encode_fid(inode, (struct fid *)f->f_handle, &size); + up_read(&inode->i_sb->s_umount); + + if ((ret == FILEID_INVALID) || (ret < 0)) return; - } f->handle_type = ret; f->handle_bytes = size * sizeof(u32); diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c index f267981a62..4388004a31 100644 --- a/fs/overlayfs/copy_up.c +++ b/fs/overlayfs/copy_up.c @@ -444,9 +444,8 @@ struct ovl_fh *ovl_encode_real_fh(struct ovl_fs *ofs, struct inode *realinode, buflen = (dwords << 2); err = -EIO; - if (WARN_ON(fh_type < 0) || - WARN_ON(buflen > MAX_HANDLE_SZ) || - WARN_ON(fh_type == FILEID_INVALID)) + if (fh_type < 0 || fh_type == FILEID_INVALID || + WARN_ON(buflen > MAX_HANDLE_SZ)) goto out_err; fh->fb.version = OVL_FH_VERSION; diff --git a/include/net/rtnetlink.h b/include/net/rtnetlink.h index 2d3eb7cb4d..06428f1cb7 100644 --- a/include/net/rtnetlink.h +++ b/include/net/rtnetlink.h @@ -2,6 +2,7 @@ #ifndef __NET_RTNETLINK_H #define __NET_RTNETLINK_H +#include #include #include @@ -67,6 +68,7 @@ static inline int rtnl_msg_family(const struct nlmsghdr *nlh) * @list: Used internally * @kind: Identifier * @netns_refund: Physical device, move to init_net on netns exit + * @peer_type: Peer device specific netlink attribute number (e.g. VETH_INFO_PEER) * @maxtype: Highest device specific netlink attribute number * @policy: Netlink policy for device specific attribute validation * @validate: Optional validation function for netlink/changelink parameters @@ -107,6 +109,7 @@ struct rtnl_link_ops { void (*setup)(struct net_device *dev); bool netns_refund; + RH_KABI_FILL_HOLE(const u16 peer_type) unsigned int maxtype; const struct nla_policy *policy; int (*validate)(struct nlattr *tb[], diff --git a/kernel.sbat b/kernel.sbat index 3a51266ac8..548c9fc048 100644 --- a/kernel.sbat +++ b/kernel.sbat @@ -1,2 +1,2 @@ sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md -kernel.almalinux,1,AlmaLinux,kernel-core,6.12.0-211.38.1.el10.x86_64,mailto:security@almalinux.org +kernel.almalinux,1,AlmaLinux,kernel-core,6.12.0-211.39.1.el10.x86_64,mailto:security@almalinux.org diff --git a/kernel/fork.c b/kernel/fork.c index ac0d19e113..4a6265fe2b 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -2107,9 +2107,11 @@ static void rv_task_fork(struct task_struct *p) static bool need_futex_hash_allocate_default(u64 clone_flags) { - if ((clone_flags & (CLONE_THREAD | CLONE_VM)) != (CLONE_THREAD | CLONE_VM)) - return false; - return true; + /* + * Allocate a default futex hash for any sibling that will + * share the parent's mm, except vfork. + */ + return (clone_flags & (CLONE_VM | CLONE_VFORK)) == CLONE_VM; } /* @@ -2492,10 +2494,6 @@ __latent_entropy struct task_struct *copy_process( if (retval) goto bad_fork_cancel_cgroup; - /* - * Allocate a default futex hash for the user process once the first - * thread spawns. - */ if (need_futex_hash_allocate_default(clone_flags)) { retval = futex_hash_allocate_default(); if (retval) diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 55cc1aa76e..10a6a25da4 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -2355,9 +2355,10 @@ int rtnl_nla_parse_ifinfomsg(struct nlattr **tb, const struct nlattr *nla_peer, } EXPORT_SYMBOL(rtnl_nla_parse_ifinfomsg); -struct net *rtnl_link_get_net(struct net *src_net, struct nlattr *tb[]) +static struct net *rtnl_link_get_net_ifla(struct nlattr *tb[]) { - struct net *net; + struct net *net = NULL; + /* Examine the link attributes and figure out which * network namespace we are talking about. */ @@ -2365,8 +2366,17 @@ struct net *rtnl_link_get_net(struct net *src_net, struct nlattr *tb[]) net = get_net_ns_by_pid(nla_get_u32(tb[IFLA_NET_NS_PID])); else if (tb[IFLA_NET_NS_FD]) net = get_net_ns_by_fd(nla_get_u32(tb[IFLA_NET_NS_FD])); - else + + return net; +} + +struct net *rtnl_link_get_net(struct net *src_net, struct nlattr *tb[]) +{ + struct net *net = rtnl_link_get_net_ifla(tb); + + if (!net) net = get_net(src_net); + return net; } EXPORT_SYMBOL(rtnl_link_get_net); @@ -3514,6 +3524,7 @@ static int rtnl_group_changelink(const struct sk_buff *skb, static int rtnl_newlink_create(struct sk_buff *skb, struct ifinfomsg *ifm, const struct rtnl_link_ops *ops, + struct net *peer_net, const struct nlmsghdr *nlh, struct nlattr **tb, struct nlattr **data, struct netlink_ext_ack *extack) @@ -3565,8 +3576,13 @@ static int rtnl_newlink_create(struct sk_buff *skb, struct ifinfomsg *ifm, dev->ifindex = ifm->ifi_index; + if (link_net) + net = link_net; + if (peer_net) + net = peer_net; + if (ops->newlink) - err = ops->newlink(link_net ? : net, dev, tb, data, extack); + err = ops->newlink(net, dev, tb, data, extack); else err = register_netdevice(dev); if (err < 0) { @@ -3615,6 +3631,44 @@ struct rtnl_newlink_tbs { struct nlattr *slave_attr[RTNL_SLAVE_MAX_TYPE + 1]; }; +static struct net *rtnl_get_peer_net(struct sk_buff *skb, + const struct rtnl_link_ops *ops, + struct nlattr *tbp[], + struct nlattr *data[], + struct netlink_ext_ack *extack) +{ + struct nlattr *tb[IFLA_MAX + 1], **attrs; + struct net *net; + int err; + + if (!data || !data[ops->peer_type]) { + attrs = tbp; + } else { + err = rtnl_nla_parse_ifinfomsg(tb, data[ops->peer_type], extack); + if (err < 0) + return ERR_PTR(err); + + if (ops->validate) { + err = ops->validate(tb, NULL, extack); + if (err < 0) + return ERR_PTR(err); + } + + attrs = tb; + } + + net = rtnl_link_get_net_ifla(attrs); + if (IS_ERR_OR_NULL(net)) + return net; + + if (!netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN)) { + put_net(net); + return ERR_PTR(-EPERM); + } + + return net; +} + static int __rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh, struct rtnl_newlink_tbs *tbs, struct netlink_ext_ack *extack) @@ -3625,6 +3679,7 @@ static int __rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh, struct net_device *master_dev; struct net *net = sock_net(skb->sk); const struct rtnl_link_ops *ops; + struct net *peer_net = NULL; struct nlattr **slave_data; char kind[MODULE_NAME_LEN]; struct net_device *dev; @@ -3703,12 +3758,20 @@ replay: if (err < 0) return err; } + + if (ops->peer_type) { + peer_net = rtnl_get_peer_net(skb, ops, tb, data, extack); + if (IS_ERR(peer_net)) + return PTR_ERR(peer_net); + } } slave_data = NULL; if (m_ops) { - if (m_ops->slave_maxtype > RTNL_SLAVE_MAX_TYPE) - return -EINVAL; + if (m_ops->slave_maxtype > RTNL_SLAVE_MAX_TYPE) { + err = -EINVAL; + goto put_net; + } if (m_ops->slave_maxtype && linkinfo[IFLA_INFO_SLAVE_DATA]) { @@ -3718,7 +3781,7 @@ replay: m_ops->slave_policy, extack); if (err < 0) - return err; + goto put_net; slave_data = tbs->slave_attr; } } @@ -3726,51 +3789,67 @@ replay: if (dev) { int status = 0; - if (nlh->nlmsg_flags & NLM_F_EXCL) - return -EEXIST; - if (nlh->nlmsg_flags & NLM_F_REPLACE) - return -EOPNOTSUPP; + if (nlh->nlmsg_flags & NLM_F_EXCL) { + err = -EEXIST; + goto put_net; + } + if (nlh->nlmsg_flags & NLM_F_REPLACE) { + err = -EOPNOTSUPP; + goto put_net; + } if (linkinfo[IFLA_INFO_DATA]) { if (!ops || ops != dev->rtnl_link_ops || - !ops->changelink) - return -EOPNOTSUPP; + !ops->changelink) { + err = -EOPNOTSUPP; + goto put_net; + } err = ops->changelink(dev, tb, data, extack); if (err < 0) - return err; + goto put_net; status |= DO_SETLINK_NOTIFY; } if (linkinfo[IFLA_INFO_SLAVE_DATA]) { - if (!m_ops || !m_ops->slave_changelink) - return -EOPNOTSUPP; + if (!m_ops || !m_ops->slave_changelink) { + err = -EOPNOTSUPP; + goto put_net; + } err = m_ops->slave_changelink(master_dev, dev, tb, slave_data, extack); if (err < 0) - return err; + goto put_net; status |= DO_SETLINK_NOTIFY; } - return do_setlink(skb, dev, ifm, extack, tb, status); + err = do_setlink(skb, dev, ifm, extack, tb, status); + goto put_net; } if (!(nlh->nlmsg_flags & NLM_F_CREATE)) { /* No dev found and NLM_F_CREATE not set. Requested dev does not exist, * or it's for a group */ - if (link_specified) - return -ENODEV; - if (tb[IFLA_GROUP]) - return rtnl_group_changelink(skb, net, - nla_get_u32(tb[IFLA_GROUP]), - ifm, extack, tb); - return -ENODEV; + if (link_specified) { + err = -ENODEV; + goto put_net; + } + if (tb[IFLA_GROUP]) { + err = rtnl_group_changelink(skb, net, + nla_get_u32(tb[IFLA_GROUP]), + ifm, extack, tb); + goto put_net; + } + err = -ENODEV; + goto put_net; } - if (tb[IFLA_MAP] || tb[IFLA_PROTINFO]) - return -EOPNOTSUPP; + if (tb[IFLA_MAP] || tb[IFLA_PROTINFO]) { + err = -EOPNOTSUPP; + goto put_net; + } if (!ops) { #ifdef CONFIG_MODULES @@ -3784,10 +3863,18 @@ replay: } #endif NL_SET_ERR_MSG(extack, "Unknown device type"); - return -EOPNOTSUPP; + err = -EOPNOTSUPP; + goto put_net; } - return rtnl_newlink_create(skb, ifm, ops, nlh, tb, data, extack); + err = rtnl_newlink_create(skb, ifm, ops, peer_net, nlh, tb, data, + extack); + +put_net: + if (peer_net) + put_net(peer_net); + + return err; } static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh, diff --git a/net/ipv6/rpl_iptunnel.c b/net/ipv6/rpl_iptunnel.c index f264c0b1f4..a9aa871367 100644 --- a/net/ipv6/rpl_iptunnel.c +++ b/net/ipv6/rpl_iptunnel.c @@ -279,7 +279,17 @@ static int rpl_input(struct sk_buff *skb) if (!dst) { ip6_route_input(skb); + + /* ip6_route_input() sets a NOREF dst; force a refcount on it + * before caching or further use. + */ + skb_dst_force(skb); dst = skb_dst(skb); + if (unlikely(!dst)) { + err = -ENETUNREACH; + goto drop; + } + if (!dst->error) { local_bh_disable(); dst_cache_set_ip6(&rlwt->cache, dst, diff --git a/net/ipv6/seg6_iptunnel.c b/net/ipv6/seg6_iptunnel.c index 3e1b999113..13ef405f46 100644 --- a/net/ipv6/seg6_iptunnel.c +++ b/net/ipv6/seg6_iptunnel.c @@ -499,7 +499,16 @@ static int seg6_input_core(struct net *net, struct sock *sk, if (!dst) { ip6_route_input(skb); + + /* ip6_route_input() sets a NOREF dst; force a refcount on it + * before caching or further use. + */ + skb_dst_force(skb); dst = skb_dst(skb); + if (unlikely(!dst)) { + err = -ENETUNREACH; + goto drop; + } /* cache only if we don't create a dst reference loop */ if (!dst->error && lwtst != dst->lwtstate) { diff --git a/redhat/kernel.changelog-10.2 b/redhat/kernel.changelog-10.2 index 6f2a73a22c..f4c4260a8b 100644 --- a/redhat/kernel.changelog-10.2 +++ b/redhat/kernel.changelog-10.2 @@ -1,3 +1,19 @@ +* Thu Jul 23 2026 CKI KWF Bot [6.12.0-211.39.1.el10_2] +- futex: Drop CLONE_THREAD requirement for private default hash alloc (Audra Mitchell) [RHEL-193518] {CVE-2026-52973} +- net: ipv6: fix NOREF dst use in seg6 and rpl lwtunnels (Antoine Tenart) [RHEL-179299] {CVE-2026-46099} +- scsi: core: Wake up the error handler when final completions race against each other (CKI Backport Bot) [RHEL-189651] {CVE-2026-23110} +- dm log: fix out-of-bounds write due to region_count overflow (CKI Backport Bot) [RHEL-188547] {CVE-2026-53059} +- rtnetlink: add missing netlink_ns_capable() check for peer netns (Guillaume Nault) [RHEL-172537] {CVE-2026-31692} +- rtnetlink: Try the outer netns attribute in rtnl_get_peer_net(). (Guillaume Nault) [RHEL-172537] {CVE-2026-31692} +- rtnetlink: fix double call of rtnl_link_get_net_ifla() (Guillaume Nault) [RHEL-172537] {CVE-2026-31692} +- netkit: Set IFLA_NETKIT_PEER_INFO to netkit_link_ops.peer_type. (Guillaume Nault) [RHEL-172537] {CVE-2026-31692} +- vxcan: Set VXCAN_INFO_PEER to vxcan_link_ops.peer_type. (Guillaume Nault) [RHEL-172537] {CVE-2026-31692} +- veth: Set VETH_INFO_PEER to veth_link_ops.peer_type. (Guillaume Nault) [RHEL-172537] {CVE-2026-31692} +- rtnetlink: Add peer_type in struct rtnl_link_ops. (Guillaume Nault) [RHEL-172537] {CVE-2026-31692} +- fs/notify: call exportfs_encode_fid with s_umount (Jay Shin) [RHEL-169188] {CVE-2025-40237} +- fs: relax assertions on failure to encode file handles (Jay Shin) [RHEL-169188] +Resolves: RHEL-169188, RHEL-172537, RHEL-179299, RHEL-188547, RHEL-189651, RHEL-193518 + * Wed Jul 22 2026 CKI KWF Bot [6.12.0-211.38.1.el10_2] - net: gro: don't merge zcopy skbs (CKI Backport Bot) [RHEL-177856] {CVE-2026-46323} Resolves: RHEL-177856 diff --git a/uki-addons.sbat b/uki-addons.sbat index d916827fca..07f56dcdd8 100644 --- a/uki-addons.sbat +++ b/uki-addons.sbat @@ -1,2 +1,2 @@ sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md -kernel-uki-virt-addons.almalinux,1,AlmaLinux,kernel-uki-virt-addons,6.12.0-211.38.1.el10.x86_64,mailto:security@almalinux.org +kernel-uki-virt-addons.almalinux,1,AlmaLinux,kernel-uki-virt-addons,6.12.0-211.39.1.el10.x86_64,mailto:security@almalinux.org diff --git a/uki.sbat b/uki.sbat index 6b3d8d31ba..531be0aad2 100644 --- a/uki.sbat +++ b/uki.sbat @@ -1,2 +1,2 @@ sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md -kernel-uki-virt.almalinux,1,AlmaLinux,kernel-uki-virt,6.12.0-211.38.1.el10.x86_64,mailto:security@almalinux.org +kernel-uki-virt.almalinux,1,AlmaLinux,kernel-uki-virt,6.12.0-211.39.1.el10.x86_64,mailto:security@almalinux.org