Lucene search
+L

Linux Distros Unpatched Vulnerability : CVE-2026-98974

🗓️ 23 Oct 2026 00:00:00Reported by TenableType 
nessus
 nessus
🔗 www.tenable.com👁 1 Views

XFS bug in XFS_IOC_EXCHANGE_RANGE's TO_EOF flag allows shared blocks beyond EOF.

Related
Refs
Code
ReporterTitlePublishedViews
Family
circl
Circl
CVE-2026-98974
23 Oct 202613:22
–circl
cve
CVE
CVE-2026-98974
23 Oct 202612:19
–cve
cvelist
Cvelist
CVE-2026-98974 xfs: fix exchange-range-to-eof file size exchange
23 Oct 202612:19
–cvelist
debiancve
Debian CVE
CVE-2026-98974
23 Oct 202612:19
–debiancve
euvd
EUVD
EUVD-2026-108768
23 Oct 202612:19
–euvd
nvd
NVD
CVE-2026-98974
23 Oct 202613:17
–nvd
osv_debian
osv_debian
DEBIAN-CVE-2026-98974
23 Oct 202613:17
–osv_debian
ptsecurity
Positive Technologies
PT-2026-121951
23 Oct 202600:00
–ptsecurity
#%NASL_MIN_LEVEL 80900
##
# (C) Tenable, Inc.
##

include('compat.inc');

if (description)
{
  script_id(371499);
  script_version("1.1");
  script_set_attribute(attribute:"plugin_modification_date", value:"2026/10/23");

  script_cve_id("CVE-2026-98974");

  script_name(english:"Linux Distros Unpatched Vulnerability : CVE-2026-98974");

  script_set_attribute(attribute:"synopsis", value:
"The Linux/Unix host has one or more packages installed with a vulnerability that the vendor indicates will not be
patched.");
  script_set_attribute(attribute:"description", value:
"The Linux/Unix host has one or more packages installed that are impacted by a vulnerability without a vendor supplied
patch available.

  - xfs: fix exchange-range-to-eof file size exchange Norbert Szetei posted a patch containing an incomplete
    description of a bug in XFS_IOC_EXCHANGE_RANGE's TO_EOF flag. The bug tricks exchange-range into modifying
    a file so that it has shared blocks starting beyond EOF, which is never allowed because files never have
    written data beyond EOF, and you can only share written data blocks. This is key to all the incorrect
    behavior that follows. Eventually I got from Norbert a description of what's going wrong: > Fair. Here it
    is with physical block numbers, 4k blocks. peer is the file > that gets rewritten and file1 is the one
    that ends up with the flag > cleared. > > Start, nothing shared: > > peer size 4096 -> [100] > file1 size
    12288 -> [200] [201] [202] > donor1 size 4096 -> [300] > donor2 size 4096 -> [400] > > 1. FICLONERANGE
    peer's block into file1's middle slot: > > peer size 4096 -> [100] > file1 size 12288 -> [200] [100] [202]
    reflink flag set > ^^^^^ both files own block 100 > > 2. XFS_IOC_EXCHANGE_RANGE file1 against donor1,
    file1_offset 0, > file2_offset 8192, length 0, TO_EOF. One block is exchanged, and the sizes > are
    exchanged with it: > > file1 size 4096 -> [200] [100] [300] reflink flag set > ^^^^^^^^^^^ still owned,
    now past the size > donor1 size 12288 -> [202] > > file1 says it is one block long while it still owns
    three. Nothing was > unmapped. file2_offset is block 2, so this exchange cannot clear a flag. > > 3.
    XFS_IOC_EXCHANGE_RANGE file1 against donor2, both offsets 0, length 4096. > By i_disk_size this is two
    one-block files exchanging everything, so > xmi_can_exchange_reflink_flags() agrees and the flag is
    cleared: > > file1 size 4096 -> [400] [100] [300] reflink flag CLEARED > donor2 size 4096 -> [200] > >
    Block 100 is still shared with peer. > > 4. pwrite(file1, 4096, 4096), which is file1's second slot, block
    100. > xfs_is_cow_inode(file1) is false, so no CoW: > > peer size 4096 -> [100] same block, new contents >
    > Block 100 is the only one that matters here. PoC below, it reads a file > called peer in the current
    directory. The filesystem needs reflink and > exchange-range, which mkfs.xfs 7.x turns on by default. So
    yes, TO_EOF is screwing up the file size even if it's actually exchanging the data block correctly. The
    following is the intended behavior of XFS_EXCHANGE_RANGE_TO_EOF, as described by its manpage: Ignore the
    length parameter. All bytes in file1_fd from file1_offset to EOF are moved to file2_fd, and file2's size
    is set to (file2_offset+(file1_length-file1_offset)). Meanwhile, all bytes in file2 from file2_offset to
    EOF are moved to file1 and file1's size is set to (file1_offset+(file2_length-file2_offset)). In other
    words, if we only exchange a portion of the file data, then we should only exchange the portion of the
    file size that relates to the exchanged data. Unfortunately, the code swaps the ondisk file size and the
    incore file sizes, which is incorrect if the caller passes in a nonzero offset. Having confused the file
    sizes, the PoC uses a second exchange-range call on what looks like a non-reflinked single-block file.
    Because the file size is set incorrectly, exchange-range thinks it's exchanging the full contents of two
    files and clears the reflink flag on the broken file. That enables an extending write of the broken file
    to rewrite the shared block that's just past EOF. This has become known colloquially as refluxfs. Once the
    file sizes are set correctly, the second exchange-range no longer thinks that it's doing a full-contents
    swap, so it won't clear the reflink flag on either of its file arguments. Norbert followed up to an
    earlier version of this patch with a second complaint about us not handling the i_disk_size state
    correctly: > The offsets are bounded against the incore i_size but subtracted from > ---truncated---
    (CVE-2026-98974)

Note that Nessus relies on the presence of the package as reported by the vendor.");
  script_set_attribute(attribute:"see_also", value:"https://security-tracker.debian.org/tracker/CVE-2026-98974");
  script_set_attribute(attribute:"solution", value:
"There is no known solution at this time.");
  script_set_attribute(attribute:"agent", value:"unix");
  script_set_cvss_base_vector("CVSS2#AV:N/AC:L/Au:N/C:P/I:P/A:P");
  script_set_cvss_temporal_vector("CVSS2#E:U/RL:U/RC:C");
  script_set_cvss3_base_vector("CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H");
  script_set_cvss3_temporal_vector("CVSS:3.0/E:U/RL:U/RC:C");
  script_set_attribute(attribute:"cvss_score_source", value:"CVE-2026-98974");

  script_set_attribute(attribute:"exploitability_ease", value:"No known exploits are available");
  script_set_attribute(attribute:"exploit_available", value:"false");
  script_set_attribute(attribute:"vendor_unpatched", value:"true");

  script_set_attribute(attribute:"vuln_publication_date", value:"2026/10/23");
  script_set_attribute(attribute:"plugin_publication_date", value:"2026/10/23");

  script_set_attribute(attribute:"plugin_type", value:"local");
  script_set_attribute(attribute:"cpe", value:"cpe:/o:debian:debian_linux:13.0");
  script_set_attribute(attribute:"cpe", value:"p-cpe:/a:debian:debian_linux:linux");
  script_set_attribute(attribute:"generated_plugin", value:"current");
  script_end_attributes();

  script_category(ACT_GATHER_INFO);
  script_family(english:"Misc.");

  script_copyright(english:"This script is Copyright (C) 2026 and is owned by Tenable, Inc. or an Affiliate thereof.");

  script_dependencies("ssh_get_info2.nasl", "set_linux_os_id.nasl");
  script_require_keys("Host/cpu", "Host/local_checks_enabled", "global_settings/vendor_unpatched", "Host/OS/identifier");
  script_require_ports("Host/OS/Debian Linux-13");

  exit(0);
}

if (!get_kb_item("global_settings/vendor_unpatched")) exit(0, "Unpatched Vulnerabilities Detection not active.");
if (!get_kb_item("Host/local_checks_enabled")) audit(AUDIT_LOCAL_CHECKS_NOT_ENABLED);
if (empty_or_null(get_one_kb_item("Host/Debian/dpkg-l"))) audit(AUDIT_PACKAGE_LIST_MISSING);

include('linux_unpatched.inc');

var distro_constraints_array = {
  "Debian Linux-13": {
    "package_manager": "dpkg-l",
    "constraints": [
      {
        "release": "13",
        "pkgs": [
          {"reference": "bpftool"},
          {"reference": "hyperv-daemons"},
          {"reference": "intel-sdsi"},
          {"reference": "libcpupower-dev"},
          {"reference": "libcpupower1"},
          {"reference": "linux-bpf-dev"},
          {"reference": "linux-config-6.12"},
          {"reference": "linux-cpupower"},
          {"reference": "linux-doc"},
          {"reference": "linux-doc-6.12"},
          {"reference": "linux-headers-4kc-malta"},
          {"reference": "linux-headers-5kc-malta"},
          {"reference": "linux-headers-6.12.107+deb13-4kc-malta"},
          {"reference": "linux-headers-6.12.107+deb13-5kc-malta"},
          {"reference": "linux-headers-6.12.107+deb13-alpha-generic"},
          {"reference": "linux-headers-6.12.107+deb13-alpha-smp"},
          {"reference": "linux-headers-6.12.107+deb13-amd64"},
          {"reference": "linux-headers-6.12.107+deb13-arm64"},
          {"reference": "linux-headers-6.12.107+deb13-arm64-16k"},
          {"reference": "linux-headers-6.12.107+deb13-armmp"},
          {"reference": "linux-headers-6.12.107+deb13-armmp-lpae"},
          {"reference": "linux-headers-6.12.107+deb13-cloud-amd64"},
          {"reference": "linux-headers-6.12.107+deb13-cloud-arm64"},
          {"reference": "linux-headers-6.12.107+deb13-common"},
          {"reference": "linux-headers-6.12.107+deb13-common-rt"},
          {"reference": "linux-headers-6.12.107+deb13-loong64"},
          {"reference": "linux-headers-6.12.107+deb13-loongson-3"},
          {"reference": "linux-headers-6.12.107+deb13-m68k"},
          {"reference": "linux-headers-6.12.107+deb13-mips32r2eb"},
          {"reference": "linux-headers-6.12.107+deb13-mips32r2el"},
          {"reference": "linux-headers-6.12.107+deb13-mips64r2eb"}
        ]
      }
    ]
  }
};

var distro_constraints_values = linux_unpatched::get_distro_constraints(distro_constraints_arr:distro_constraints_array);
if (empty_or_null(distro_constraints_values)) audit(AUDIT_HOST_NOT, 'affected');

var third_party_support = get_kb_item('Host/OS/extended-third-party');
if (!empty_or_null(third_party_support)) {
    var third_party_vendors = distro_constraints_values['third_party'];
    if (!empty_or_null(third_party_vendors)) {
        var vendor;
        foreach vendor (third_party_vendors) {
            if (vendor == third_party_support) exit(0, 'A third party management patch is available for this vulnerability from ' + vendor + '.\n');
        }
    }
}

var report = linux_unpatched::check_unpatched_constraints(distro_constraints_values:distro_constraints_values);

if (!empty_or_null(report))
{
  security_report_v4(
      port       : 0,
      severity   : SECURITY_WARNING,
      extra      : report
  );
  exit(0);
}
else
{
  audit(AUDIT_HOST_NOT, 'affected');
}

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

23 Oct 2026 00:00Current
5.8Medium risk
Vulners AI Score5.8
CVSS 3.17.8
EPSS0.00209
1