{
  "schema_version": "1.6.1",
  "id": "RPI-CVE-2025-40149",
  "modified": "2026-10-09T11:39:44Z",
  "upstream": [
    "CVE-2025-40149"
  ],
  "published": "2025-11-12T10:24:04Z",
  "summary": "tls: Use __sk_dst_get() and dst_dev_rcu() in get_netdev_for_sock().",
  "details": "In the Linux kernel, the following vulnerability has been resolved:\n\ntls: Use __sk_dst_get() and dst_dev_rcu() in get_netdev_for_sock().\n\nget_netdev_for_sock() is called during setsockopt(),\nso not under RCU.\n\nUsing sk_dst_get(sk)->dev could trigger UAF.\n\nLet's use __sk_dst_get() and dst_dev_rcu().\n\nNote that the only ->ndo_sk_get_lower_dev() user is\nbond_sk_get_lower_dev(), which uses RCU.",
  "severity": [
    {
      "type": "CVSS_V3",
      "score": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H"
    }
  ],
  "affected": [
    {
      "package": {
        "ecosystem": "Raspberry Pi OS:12",
        "name": "linux"
      },
      "versions": [
        "1:6.1.47-1+rpt4"
      ],
      "ecosystem_specific": {
        "binaries": [
          {
            "binary_name": "linux-image-6.1.0-rpi3-rpi-2712",
            "binary_version": "1:6.1.47-1+rpt4"
          },
          {
            "binary_name": "linux-image-6.1.0-rpi3-rpi-v6",
            "binary_version": "1:6.1.47-1+rpt4"
          },
          {
            "binary_name": "linux-image-6.1.0-rpi3-rpi-v7",
            "binary_version": "1:6.1.47-1+rpt4"
          },
          {
            "binary_name": "linux-image-6.1.0-rpi3-rpi-v7l",
            "binary_version": "1:6.1.47-1+rpt4"
          },
          {
            "binary_name": "linux-image-6.1.0-rpi3-rpi-v8",
            "binary_version": "1:6.1.47-1+rpt4"
          }
        ]
      },
      "database_specific": {
        "per_version": {
          "1:6.1.47-1+rpt4": {
            "linux_commit": "655fc658a15ae7a6f37103754adb39ba52a9a14e",
            "upstream_version": "6.1.47",
            "assessment": "commit ancestry (strak rule)",
            "upstream_fixed": "6.1.161",
            "compiled_filter": false
          }
        }
      }
    }
  ],
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://www.cve.org/CVERecord?id=CVE-2025-40149"
    },
    {
      "type": "FIX",
      "url": "https://git.kernel.org/stable/c/2b1bef126bbb8d0da51491357559126d567c1dee"
    },
    {
      "type": "FIX",
      "url": "https://git.kernel.org/stable/c/e37ca0092ddace60833790b4ad7a390408fb1be9"
    },
    {
      "type": "FIX",
      "url": "https://git.kernel.org/stable/c/13159c7125636371543a82cb7bbae00ab36730cc"
    },
    {
      "type": "FIX",
      "url": "https://git.kernel.org/stable/c/f09cd209359a23f88d4f3fa3d2379d057027e53c"
    },
    {
      "type": "FIX",
      "url": "https://git.kernel.org/stable/c/feb474ddbf26b51f462ae2e60a12013bdcfc5407"
    },
    {
      "type": "FIX",
      "url": "https://git.kernel.org/stable/c/c65f27b9c3be2269918e1cbad6d8884741f835c5"
    }
  ],
  "database_specific": {
    "source": "https://git.kernel.org/pub/scm/linux/security/vulns.git",
    "upstream_modified": "2026-08-05T12:19:11Z",
    "severity": {
      "source": "kernel CNA",
      "cvss_v3_score": 7.8,
      "cvss_v3_severity": "High",
      "scenario": "AV:L - `get_netdev_for_sock()` has exactly two callers, `tls_set_device_offload()` and `tls_set_device_offload_rx()`, both reachable only from `setsockopt(SOL_TLS, TLS_TX/TLS_RX)` in process context \u2014 no received TLS record or remote peer data drives this path. The racing `dst_dev_put()` side likewise requires local netlink link/route teardown, so the entire attack is delivered through local syscalls.\nAC:L - The attacker controls both sides of the race \u2014 one thread repeatedly issues `setsockopt(TLS_TX)` on TCP sockets whose `sk_dst_cache` points at a veth while another deletes that veth in the attacker's own netns \u2014 and can retry indefinitely until the window between reading `dst->dev` and the `netdev_ref_replace()`/free is hit. `CONFIG_TLS_DEVICE` is a routinely enabled distro option, and the vulnerable read happens before any NIC-capability or `IFF_UP` gate, so no special hardware is required.\nPR:L - An ordinary unprivileged local account suffices: attaching the tls ULP and calling `setsockopt(SOL_TLS, ...)` requires no capability once the ULP is registered (the `capable(CAP_NET_ADMIN)` check in `__tcp_ulp_find_autoload()` gates only module autoload), and the CAP_NET_ADMIN needed to create and delete the veth is obtained in the attacker's own user+net namespace via `unshare -Urn`, not real root.\nUI:N - Exploitation is driven entirely by the attacker's own threads issuing socket syscalls and netlink link/route operations; no victim action, mount, or file open is involved.\nS:U - The use-after-free is on a kernel `struct net_device` and its consequences remain within the kernel's own security authority, with no crossing of a VM, IOMMU, or sandbox boundary.\nC:H - This is a use-after-free on a freed, heap-sprayable `net_device`: `netdev_sk_get_lower_dev()` reads `dev->netdev_ops` from freed memory and the caller subsequently reads `netdev->features` and `netdev->flags`, whose values are observable through the setsockopt return code and the resulting offload state, giving an attacker-groomable read of reclaimed kernel memory.\nI:H - The freed object is used for two indirect calls \u2014 `ops->ndo_sk_get_lower_dev(dev, sk)` and later `netdev->tlsdev_ops->tls_dev_add(...)` \u2014 both function pointers loaded out of reclaimed memory, and `dev_hold(lowest_dev)` performs a refcount increment inside the freed allocation, together yielding control-flow-hijack and write primitives once the slab is sprayed.\nA:H - Dereferencing and indirect-calling through a freed `net_device` reliably oopses the kernel even when not weaponized, and the race is repeatable at will by an unprivileged local user for a persistent denial of service."
    }
  }
}
