Lucene search
+L

Unity Linux 20.1070e Security Update: kernel (UTSA-2026-142559)

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

Out-of-bounds access in the Linux kernel hid-rmi driver.

Related
Refs
Code
#%NASL_MIN_LEVEL 80900
##
# (C) Tenable, Inc.
##

include('compat.inc');

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

  script_cve_id("CVE-2026-90000");

  script_name(english:"Unity Linux 20.1070e Security Update: kernel (UTSA-2026-142559)");

  script_set_attribute(attribute:"synopsis", value:
"The Unity Linux host is missing one or more security updates.");
  script_set_attribute(attribute:"description", value:
"The Unity Linux 20 host has a package installed that is affected by a vulnerability as referenced in the
UTSA-2026-142559 advisory.

    In the Linux kernel, the following vulnerability has been resolved:

    HID: rmi: fix OOB access with undersized RMI reports

    The hid-rmi driver sizes its writeReport/readReport buffer purely from
    the report descriptor supplied by the device, with no minimum bound:

            data->input_report_size  = hid_report_len(input_report);
            data->output_report_size = hid_report_len(output_report);
            alloc_size = data->output_report_size + data->input_report_size;
            data->writeReport = devm_kzalloc(&hdev->dev, alloc_size, GFP_KERNEL);
            data->readReport = data->writeReport + data->output_report_size;

    but then reads and writes fixed offsets into it.  A device declaring a
    1-byte output and a 1-byte input report makes hid_report_len() return 2
    for each, so alloc_size is 4, while rmi_set_page() -- reached
    unconditionally at probe time through rmi_input_configured() -- stores
    writeReport[4] and rmi_hid_read_block() stores writeReport[0..5].  Since
    readReport lives at writeReport + output_report_size, those stores also
    corrupt the window the next reply is parsed out of.

    The read path is worse: the copy length comes from readReport[1], which
    the device fills in and can be up to 255, and the copy starts at
    &readReport[2] with no regard for input_report_size, so it runs past the
    end of the allocation into adjacent slab objects.  This does not even
    need a lying device -- rmi_f01_probe() issues a fixed 21-byte register
    read, so any device declaring an input report smaller than 23 bytes
    reads out of bounds even when it answers truthfully.  Those bytes become
    the register values the RMI core acts on: rmi_f01_probe() prints them to
    the kernel log as the product id and exports them through the mode 0444
    sysfs attribute of the same name, and rmi_driver_set_irq_bits() sends
    them back to the device as the interrupt mask, so an undersized report
    descriptor leaks heap contents both to unprivileged userspace and to the
    device itself.

    The write path has no bound either: rmi_hid_write_block() copies an
    unbounded len to &writeReport[4], and the largest caller a device can
    drive at probe time is rmi_driver_set_irq_bits(), whose length is
    derived from the interrupt source counts the device declares in its Page
    Description Table.

    Finally, the read loop cannot terminate on a zero-length reply: such a
    reply copies nothing and advances neither bytes_read nor bytes_needed,
    and because a reply did arrive the one second wait_event_timeout() does
    not fire either, so a device answering 0 forever keeps the loop running
    inside the probe worker with page_mutex held.  khungtaskd does not
    notice, because every reply wakes the task.

    Reject reports too small for what the driver builds -- 6 output bytes
    for the write reports and 3 input bytes for the read handshake -- at
    probe time, clamp the write and the read copy to the report sizes the
    device declared, and treat a zero-length reply as an error.  A device
    refused this way is started as an ordinary HID device, like one that
    does not carry the RMI report ids at all.

    RMI_DEVICE must not be left set in device_flags on that path, because
    rmi_input_configured() would then run the RMI setup and reach
    rmi_set_page(), which writes the writeReport buffer the refusal just
    skipped allocating.  The bit can arrive set: rmi_probe() copies
    id->driver_data into device_flags before the report checks, and a bind
    through the new_id sysfs attribute can supply driver_data with
    RMI_DEVICE (BIT(0)) set.  Strip the bit where driver_data is copied, so
    RMI_DEVICE keeps meaning exactly this probe validated the reports; the
    three jumps to start that predate this patch are covered as well.

    The error path also clears RMI_READ_DATA_PENDING on its way out, because
    that flag is what the wait at the top of the loop tests: leaving it set
    would make every later wait_event_timeout() return immediately on the
    stale reply and kill the read path for the rest of the device's life.

    Clamping does not regress working hardware: the read loop already
    handles
    ---truncated---

Tenable has extracted the preceding description block directly from the Unity Linux security advisory.

Note that Nessus has not tested for this issue but has instead relied only on the application's self-reported version
number.");
  # https://src.uniontech.com/#/security_advisory_detail?utsa_id=UTSA-2026-142559
  script_set_attribute(attribute:"see_also", value:"http://www.nessus.org/u?a633a387");
  # https://lore.kernel.org/linux-cve-announce/2026091659-CVE-2026-90000-54ee@gregkh
  script_set_attribute(attribute:"see_also", value:"http://www.nessus.org/u?61fdd326");
  script_set_attribute(attribute:"see_also", value:"https://nvd.nist.gov/vuln/detail/CVE-2026-90000");
  script_set_attribute(attribute:"solution", value:
"Update the affected kernel package.");
  script_set_cvss_base_vector("CVSS2#AV:A/AC:L/Au:N/C:C/I:C/A:C");
  script_set_cvss_temporal_vector("CVSS2#E:U/RL:OF/RC:C");
  script_set_cvss3_base_vector("CVSS:3.0/AV:A/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:O/RC:C");
  script_set_attribute(attribute:"cvss_score_source", value:"CVE-2026-90000");

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

  script_set_attribute(attribute:"vuln_publication_date", value:"2026/09/16");
  script_set_attribute(attribute:"patch_publication_date", value:"2026/10/22");
  script_set_attribute(attribute:"plugin_publication_date", value:"2026/10/22");

  script_set_attribute(attribute:"plugin_type", value:"local");
  script_set_attribute(attribute:"generated_plugin", value:"current");
  script_end_attributes();

  script_category(ACT_GATHER_INFO);
  script_family(english:"Unity Linux Local Security Checks");

  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");
  script_require_keys("Host/local_checks_enabled", "Host/UOS-Server/release", "Host/UOS-Server/rpm-list", "Host/cpu");

  exit(0);
}
include('rpm2.inc');

if (!get_kb_item('Host/local_checks_enabled')) audit(AUDIT_LOCAL_CHECKS_NOT_ENABLED);
var os_product = get_kb_item('installed_os/local/SSH/0/product');
if (isnull(os_product) || 'UOS Server' >!< os_product) audit(AUDIT_OS_NOT, 'UOS Server');
var os_version = get_kb_item('installed_os/local/SSH/0/version');
if (isnull(os_version)) audit(AUDIT_UNKNOWN_APP_VER, 'UOS Server');
if (! preg(pattern:"^(20.1070e)([^0-9]|$)", string:os_version)) audit(AUDIT_OS_NOT, 'UOS Server 20.1070e', 'UOS Server ' + os_version);

if (!get_kb_item('Host/UOS-Server/rpm-list')) audit(AUDIT_PACKAGE_LIST_MISSING);

var cpu = get_kb_item('Host/cpu');
if (isnull(cpu)) audit(AUDIT_UNKNOWN_ARCH);
if ('aarch64' >!< cpu && 'amd64' >!< cpu && 'sw_64' >!< cpu && 'x86_64' >!< cpu) audit(AUDIT_LOCAL_CHECKS_NOT_IMPLEMENTED, 'UOS Server', cpu);


var constraints = [
  {
    'release': '20',
    'sp': '1070e',
    'pkgs': [
      {'reference':'kernel-5.10.0-79.27.uel20', 'sp':'1070e', 'cpu':'aarch64', 'rpm_spec_vers_cmp':TRUE},
      {'reference':'kernel-5.10.0-79.27.uel20', 'sp':'1070e', 'cpu':'amd64', 'rpm_spec_vers_cmp':TRUE},
      {'reference':'kernel-5.10.0-79.27.uel20', 'sp':'1070e', 'cpu':'sw_64', 'rpm_spec_vers_cmp':TRUE},
      {'reference':'kernel-5.10.0-79.27.uel20', 'sp':'1070e', 'cpu':'x86_64', 'rpm_spec_vers_cmp':TRUE}
    ]
  }
];

var os_release = get_one_kb_item('installed_os/local/SSH/0/release');
var os_sp = get_one_kb_item('Host/*/minor_release');

var flag = 0;
var reference;
var sp;
var _cpu;
var el_string;
var rpm_spec_vers_cmp;
var epoch;
var allowmaj;
var exists_check;
var cves;
foreach var constraint ( constraints ) {
  # Check that the target release is equal to the affected release
  if (!empty_or_null(constraint['release'])){
    if (constraint['release'] != os_release) continue;
  }
  if (!empty_or_null(constraint['sp'])){
    if (constraint['sp'] != os_sp) continue;
  }
  foreach var pkg ( constraint['pkgs'] ) {
    reference = NULL;
    sp = NULL;
    _cpu = NULL;
    el_string = NULL;
    rpm_spec_vers_cmp = NULL;
    epoch = NULL;
    allowmaj = NULL;
    exists_check = NULL;
    cves = NULL;
    if (!empty_or_null(pkg['reference'])) reference = pkg['reference'];
    if (!empty_or_null(pkg['sp'])) sp = pkg['sp'];
    if (!empty_or_null(pkg['cpu'])) _cpu = pkg['cpu'];
    if (!empty_or_null(pkg['el_string'])) el_string = pkg['el_string'];
    if (!empty_or_null(pkg['rpm_spec_vers_cmp'])) rpm_spec_vers_cmp = pkg['rpm_spec_vers_cmp'];
    if (!empty_or_null(pkg['epoch'])) epoch = pkg['epoch'];
    if (!empty_or_null(pkg['allowmaj'])) allowmaj = pkg['allowmaj'];
    if (!empty_or_null(pkg['exists_check'])) exists_check = pkg['exists_check'];
    if (!empty_or_null(pkg['cves'])) cves = pkg['cves'];
    if (reference &&
        ## (no known rpm to check OR known rpm_exists)
        (!exists_check || rpm_exists(rpm:exists_check)) &&
        rpm_check(sp:sp, cpu:_cpu, reference:reference, epoch:epoch, el_string:el_string, rpm_spec_vers_cmp:rpm_spec_vers_cmp, allowmaj:allowmaj, cves:cves)) flag++;
  }
}


if (flag)
{
  security_report_v4(
      port       : 0,
      severity   : SECURITY_HOLE,
      extra      : rpm_report_get()
  );
  exit(0);
}
else
{
  var tested = pkg_tests_get();
  if (tested) audit(AUDIT_PACKAGE_NOT_AFFECTED, tested);
  else audit(AUDIT_PACKAGE_NOT_INSTALLED, 'kernel');
}

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

22 Oct 2026 00:00Current
6.1Medium risk
Vulners AI Score6.1
CVSS 3.18.8
EPSS0.00354
4