← Back to CVE Explorer

CVE-2025-68359

Full vulnerability record from the local CVENow database.

Description

In the Linux kernel, the following vulnerability has been resolved: btrfs: fix double free of qgroup record after failure to add delayed ref head In the previous code it was possible to incur into a double kfree() scenario when calling add_delayed_ref_head(). This could happen if the record was reported to already exist in the btrfs_qgroup_trace_extent_nolock() call, but then there was an error later on add_delayed_ref_head(). In this case, since add_delayed_ref_head() returned an error, the caller went to free the record. Since add_delayed_ref_head() couldn't set this kfree'd pointer to NULL, then kfree() would have acted on a non-NULL 'record' object which was pointing to memory already freed by the callee. The problem comes from the fact that the responsibility to kfree the object is on both the caller and the callee at the same time. Hence, the fix for this is to shift the ownership of the 'qrecord' object out of the add_delayed_ref_head(). That is, we will never attempt to kfree() the given object inside of this function, and will expect the caller to act on the 'qrecord' object on its own. The only exception where the 'qrecord' object cannot be kfree'd is if it was inserted into the tracing logic, for which we already have the 'qrecord_inserted_ret' boolean to account for this. Hence, the caller has to kfree the object only if add_delayed_ref_head() reports not to have inserted it on the tracing logic. As a side-effect of the above, we must guarantee that 'qrecord_inserted_ret' is properly initialized at the start of the function, not at the end, and then set when an actual insert happens. This way we avoid 'qrecord_inserted_ret' having an invalid value on an early exit. The documentation from the add_delayed_ref_head() has also been updated to reflect on the exact ownership of the 'qrecord' object.

Severity
CRITICAL
CVSS score
9.8 (v3.1)
Vulnerability status
Deferred
Source identifier
416baaa9-dc9f-4396-8d5f-8c081fb06d67
Published
2025-12-24 11:15:59.283000
Last modified
2026-10-21 13:18:22.890000
View original CVE JSON
{
  "id": "CVE-2025-68359",
  "sourceIdentifier": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
  "published": "2025-12-24T11:15:59.283",
  "lastModified": "2026-10-21T13:18:22.890",
  "vulnStatus": "Deferred",
  "cveTags": [],
  "descriptions": [
    {
      "lang": "en",
      "value": "In the Linux kernel, the following vulnerability has been resolved:\n\nbtrfs: fix double free of qgroup record after failure to add delayed ref head\n\nIn the previous code it was possible to incur into a double kfree()\nscenario when calling add_delayed_ref_head(). This could happen if the\nrecord was reported to already exist in the\nbtrfs_qgroup_trace_extent_nolock() call, but then there was an error\nlater on add_delayed_ref_head(). In this case, since\nadd_delayed_ref_head() returned an error, the caller went to free the\nrecord. Since add_delayed_ref_head() couldn't set this kfree'd pointer\nto NULL, then kfree() would have acted on a non-NULL 'record' object\nwhich was pointing to memory already freed by the callee.\n\nThe problem comes from the fact that the responsibility to kfree the\nobject is on both the caller and the callee at the same time. Hence, the\nfix for this is to shift the ownership of the 'qrecord' object out of\nthe add_delayed_ref_head(). That is, we will never attempt to kfree()\nthe given object inside of this function, and will expect the caller to\nact on the 'qrecord' object on its own. The only exception where the\n'qrecord' object cannot be kfree'd is if it was inserted into the\ntracing logic, for which we already have the 'qrecord_inserted_ret'\nboolean to account for this. Hence, the caller has to kfree the object\nonly if add_delayed_ref_head() reports not to have inserted it on the\ntracing logic.\n\nAs a side-effect of the above, we must guarantee that\n'qrecord_inserted_ret' is properly initialized at the start of the\nfunction, not at the end, and then set when an actual insert\nhappens. This way we avoid 'qrecord_inserted_ret' having an invalid\nvalue on an early exit.\n\nThe documentation from the add_delayed_ref_head() has also been updated\nto reflect on the exact ownership of the 'qrecord' object."
    },
    {
      "lang": "es",
      "value": "En el kernel de Linux, la siguiente vulnerabilidad ha sido resuelta:\n\nbtrfs: corrige la doble liberación de un registro de qgroup después de fallar al añadir un 'delayed ref head'\n\nEn el código anterior era posible incurrir en un escenario de doble kfree() al llamar a add_delayed_ref_head(). Esto podría ocurrir si se informaba que el registro ya existía en la llamada a btrfs_qgroup_trace_extent_nolock(), pero luego había un error más tarde en add_delayed_ref_head(). En este caso, dado que add_delayed_ref_head() devolvió un error, el llamador procedió a liberar el registro. Dado que add_delayed_ref_head() no pudo establecer este puntero 'kfree'd' a NULL, entonces kfree() habría actuado sobre un objeto 'record' no-NULL que apuntaba a memoria ya liberada por el llamado.\n\nEl problema surge del hecho de que la responsabilidad de liberar el objeto con kfree recae tanto en el llamador como en el llamado al mismo tiempo. Por lo tanto, la solución para esto es trasladar la propiedad del objeto 'qrecord' fuera de add_delayed_ref_head(). Es decir, nunca intentaremos liberar con kfree() el objeto dado dentro de esta función, y esperaremos que el llamador actúe sobre el objeto 'qrecord' por su cuenta. La única excepción en la que el objeto 'qrecord' no puede ser liberado con kfree es si fue insertado en la lógica de rastreo, para lo cual ya tenemos el booleano 'qrecord_inserted_ret' que da cuenta de esto. Por lo tanto, el llamador tiene que liberar el objeto con kfree solo si add_delayed_ref_head() informa no haberlo insertado en la lógica de rastreo.\n\nComo efecto secundario de lo anterior, debemos garantizar que 'qrecord_inserted_ret' se inicialice correctamente al inicio de la función, no al final, y luego se establezca cuando ocurra una inserción real. De esta manera evitamos que 'qrecord_inserted_ret' tenga un valor inválido en una salida temprana.\n\nLa documentación de add_delayed_ref_head() también ha sido actualizada para reflejar la propiedad exacta del objeto 'qrecord'."
    }
  ],
  "affected": [
    {
      "source": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
      "affectedData": [
        {
          "vendor": "Linux",
          "product": "Linux",
          "defaultStatus": "unaffected",
          "programFiles": [
            "fs/btrfs/delayed-ref.c"
          ],
          "repo": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git",
          "versions": [
            {
              "version": "6ef8fbce010421bf742b12b8f8f2b2d2ff154845",
              "lessThan": "82d46660ebd94c269e3f25a77eb563621d8e67e3",
              "versionType": "git",
              "status": "affected"
            },
            {
              "version": "6ef8fbce010421bf742b12b8f8f2b2d2ff154845",
              "lessThan": "7617680769e3119dfb3b43a2b7c287ce2242211c",
              "versionType": "git",
              "status": "affected"
            },
            {
              "version": "6ef8fbce010421bf742b12b8f8f2b2d2ff154845",
              "lessThan": "364685c4c2d9c9f4408d95451bcf42fdeebc3ebb",
              "versionType": "git",
              "status": "affected"
            },
            {
              "version": "6ef8fbce010421bf742b12b8f8f2b2d2ff154845",
              "lessThan": "725e46298876a2cc1f1c3fb22ba69d29102c3ddf",
              "versionType": "git",
              "status": "affected"
            }
          ]
        },
        {
          "vendor": "Linux",
          "product": "Linux",
          "defaultStatus": "affected",
          "programFiles": [
            "fs/btrfs/delayed-ref.c"
          ],
          "repo": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git",
          "versions": [
            {
              "version": "6.12",
              "status": "affected"
            },
            {
              "version": "0",
              "lessThan": "6.12",
              "versionType": "semver",
              "status": "unaffected"
            },
            {
              "version": "6.12.114",
              "lessThanOrEqual": "6.12.*",
              "versionType": "semver",
              "status": "unaffected"
            },
            {
              "version": "6.17.13",
              "lessThanOrEqual": "6.17.*",
              "versionType": "semver",
              "status": "unaffected"
            },
            {
              "version": "6.18.2",
              "lessThanOrEqual": "6.18.*",
              "versionType": "semver",
              "status": "unaffected"
            },
            {
              "version": "6.19",
              "lessThanOrEqual": "*",
              "versionType": "original_commit_for_fix",
              "status": "unaffected"
            }
          ]
        }
      ]
    }
  ],
  "metrics": {
    "cvssMetricV31": [
      {
        "source": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
        "type": "Secondary",
        "cvssData": {
          "version": "3.1",
          "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
          "baseScore": 9.8,
          "baseSeverity": "CRITICAL",
          "attackVector": "NETWORK",
          "attackComplexity": "LOW",
          "privilegesRequired": "NONE",
          "userInteraction": "NONE",
          "scope": "UNCHANGED",
          "confidentialityImpact": "HIGH",
          "integrityImpact": "HIGH",
          "availabilityImpact": "HIGH"
        },
        "exploitabilityScore": 3.9,
        "impactScore": 5.9
      }
    ]
  },
  "references": [
    {
      "url": "https://git.kernel.org/stable/c/364685c4c2d9c9f4408d95451bcf42fdeebc3ebb",
      "source": "416baaa9-dc9f-4396-8d5f-8c081fb06d67"
    },
    {
      "url": "https://git.kernel.org/stable/c/725e46298876a2cc1f1c3fb22ba69d29102c3ddf",
      "source": "416baaa9-dc9f-4396-8d5f-8c081fb06d67"
    },
    {
      "url": "https://git.kernel.org/stable/c/7617680769e3119dfb3b43a2b7c287ce2242211c",
      "source": "416baaa9-dc9f-4396-8d5f-8c081fb06d67"
    },
    {
      "url": "https://git.kernel.org/stable/c/82d46660ebd94c269e3f25a77eb563621d8e67e3",
      "source": "416baaa9-dc9f-4396-8d5f-8c081fb06d67"
    }
  ]
}