From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-pf1-f172.google.com (mail-pf1-f172.google.com [209.85.210.172]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 05FFC381EB8 for ; Sun, 26 Jul 2026 11:36:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.172 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785065794; cv=none; b=RJy+wNGD/6fE6/u9AM7DLRNyKVkzd8isQPXKy7FxXWs+NUew22evy1CszFuProf6oe+tbt0/3k79fgPbwG2AzI+dDtzyhRo/a0+GJDRLlqKKNBIUy5vn5fXNdq1bdXgLU7p7wtVk3OoT/cRXTXuPVGhY+mYaaIHPWr6dmGxWlWc= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785065794; c=relaxed/simple; bh=PdnK50oA4aFSHZ0sz/xkxC2UJ+Kx0nvxAsO7+oQ5kI0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=J84zPymnj2yg0TZN/yQeStXwEXi0CDi1kwEzQ8s16PIlh8CVGuDmXiXDBH1XYLEKZbEwx9ownX12CVG5zvajBoEMaUItH6vbOWE0/7ifpKa6x/cnpLf5ndmF+K0AW8sB4rqDciePFW1wkYbjOgS2TU2mRe5TX5FAqgM/mITLUZ0= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=Ft2hkL8z; arc=none smtp.client-ip=209.85.210.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="Ft2hkL8z" Received: by mail-pf1-f172.google.com with SMTP id d2e1a72fcca58-84830c774a0so1812525b3a.1 for ; Sun, 26 Jul 2026 04:36:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1785065792; x=1785670592; darn=vger.kernel.org; h=content-transfer-encoding:content-type:mime-version:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc:subject :date:message-id:reply-to:content-type; bh=ZpZ8cl8NdFknWl7FIQEBjS+A4S/OlaNCwNqgkfiNXr8=; b=Ft2hkL8z8GT3HlDdQ3SRaP4Avnsh2Rv2zq4WDkHp+gPiA0eAJok88XXlUoWaKLZwHw GAzyMOga0P0QdoBhYI6SC71Y8ltyD1RZv85J/SNUWsmrClPKTb0buTCn3GhT0MOdG1vC DYqkAUoS4SCJ0HHLYEqh7nwqpu+SrjJajB3Dah+eo1YVMWuyod7TU7PFFb+iyLwLFFmw W7Nlw1Z8PLgoch3OADElILy8Zc45SjQue0bJE3MO4pfo8+8/wzeX/fCAyV+12gYpa/MY RR19RBdeIxiYCCAn+7Hdh7l5ZVGy+DOW91WCqMNxrzIFg/7fcpw02WUQv5inpNtD6dzL z1eg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1785065792; x=1785670592; h=content-transfer-encoding:content-type:mime-version:references :in-reply-to:message-id:date:subject:cc:to:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=ZpZ8cl8NdFknWl7FIQEBjS+A4S/OlaNCwNqgkfiNXr8=; b=PNdKxgMTrbUijEXcStF8ywqWENb2unxQ25uNjBnDyreTP0wlnQVmVuUdYMsQw6L0Jl Iv9Qeqoh7dmNodb0YwgT+WzGTl7HtLpGMDa+EI41oTf1VscyK4BNJEt478qQey4UEg2R 21fa6881RdVjVOj2jrJbAs1NPGKe+xGDbwwVhWSMhfVuPnzc+uE9USt9vNI+l0vuez/z CpOVea62b3dEtXIdRBZkjlrsg7IwjLQodlflL5sOCP6ybiam+kQpHKuscfxGHP6Vh6fQ qmUlCQs+PM6c9tIjbg3R9vPRikKFLCEKl2EHxRbgBhW8WJpQGhEP8RcxgyJVrimmYhBE 3w4Q== X-Forwarded-Encrypted: i=1; AHgh+RoSkfrKGjpZQHMc9KfuIKXqkinwbv86T4jOcX717F47nR6feSJFn5raHoTqbxaIEjlkiouEJb/SXrs=@vger.kernel.org X-Gm-Message-State: AOJu0YzFOGN9tz7dIyJGLZzIOWfXYLzBdAJxBYnpfM4O3GKeQgWWgmjd KoeFcZuk6WWhhpaW1fgpupSem8SnQ03aLzvDoaJpVUfPrMK1fnBGy+zp X-Gm-Gg: AR+sD13iib2tTpdR52kXLRadGL2WecGGBvhHgjvGppRU10h302zfzUiwMHcZ+MUbPQq ELE3HOoU++PmlzaSwJRHQRy/XpFtmNYEPfnP/zIBalNNyd0FrWS0bNQ+S3lK2dyj9oaE47gEXr5 TI7oLnvn+ZQHUCpiGDhwEXCdXmlRGrMsaqNdfY2OAQ/o/xesAEvEsO4d7LVkYYUvtJUV5blQdtt ukxuPCNCx+/E0WjK0ATftOy+lxmCXB3kXfRf2gRGHoQfLo09+IscDLSIPPbG1ZfnRfQpYyqoEG5 Ev7sm1xoi89UxN0ucFyutcXU3i2cSrd2ttmXI/Ts38NFe//MNYMdNYcwDqteQ/SsrQkYAkC436T Cl9z5xEoOdY+sEnBEzuZOoXgnJ4hWdYdzRp0ohad5UQ6aJ8Y9mXQIDrVWRCTMoiqjoZAm80yhCJ qrwiqtHf+NOdu2SeRPrJFDhXvk0OY14tHrnc2u5fs5VHYrOKti3A+SwkFlo3r3Hr2oJ0frdNa7k A== X-Received: by 2002:a05:6a00:1826:b0:847:9c06:2bef with SMTP id d2e1a72fcca58-84e59474684mr3819057b3a.29.1785065792127; Sun, 26 Jul 2026 04:36:32 -0700 (PDT) Received: from localhost.localdomain (211-20-143-81.hinet-ip.hinet.net. [211.20.143.81]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-84e532585edsm1785051b3a.4.2026.07.26.04.36.26 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Sun, 26 Jul 2026 04:36:30 -0700 (PDT) From: =?UTF-8?q?HE=20WEI=20=28=E3=82=AE=E3=82=AB=E3=82=AF=29?= To: Hans de Goede , Greg Kroah-Hartman , Andi Shyti Cc: Sakari Ailus , linux-usb@vger.kernel.org, linux-i2c@vger.kernel.org, linux-kernel@vger.kernel.org, HE WEI , stable@vger.kernel.org Subject: [PATCH v2 3/3] usb: misc: usbio: bound the debug hex dumps by the received length Date: Sun, 26 Jul 2026 20:35:09 +0900 Message-ID: <20260726113511.57596-4-skyexpoc@gmail.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260726113511.57596-1-skyexpoc@gmail.com> References: <20260726113511.57596-1-skyexpoc@gmail.com> Precedence: bulk X-Mailing-List: linux-usb@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit usbio_ctrl_msg() and usbio_bulk_msg() hex dump the reply with "%*phN", using a length the device supplied and that has not been validated yet: ret = usb_control_msg(usbio->udev, pipe, 0, request | USB_DIR_IN, 0, 0, cpkt, cpkt_len, USBIO_CTRLXFER_TIMEOUT); dev_dbg(usbio->dev, "control in %d hdr %*phN data %*phN\n", ret, (int)sizeof(*cpkt), cpkt, (int)cpkt->len, cpkt->data); cpkt->len is a u8 read back out of usbio->ctrlbuf after the IN transfer, and bpkt_len in usbio_bulk_msg() is le16_to_cpu(bpkt->len) read out of usbio->rxbuf. Both are handed to "%*phN" as the field width. hex_string() in lib/vsprintf.c caps that at 64, and dereferences every byte up to that cap regardless of how much room the output buffer has: if (spec.field_width > 0) len = min(spec.field_width, 64); for (i = 0; i < len; ++i) { if (buf < end) *buf = hex_asc_hi(addr[i]); So the dump reads up to byte 67 of ctrlbuf and byte 68 of rxbuf. Both buffers are sized from the endpoint packet sizes, so this is out of bounds whenever ep0 wMaxPacketSize is below 68 and whenever the bulk in endpoint is below 69. That covers every low, full and high speed ep0 (8, 16, 32 or 64) and the bulk sizes the supported bridges actually use (64, or 63 for the Synaptics Sabre via USBIO_QUIRK_BULK_MAXP_63). A device answering one of the five usbio_ctrl_msg() calls in usbio_probe() with cpkt->len = 255 therefore leaks up to 60 bytes of adjacent slab memory into the kernel log during enumeration, before any user space is involved. On the bulk path a reply claiming bpkt->len = 0xffff reads 5 bytes past a 64 byte rxbuf. Unlike the endpoint size issues this needs no malformed descriptor at all; it only needs the dev_dbg() calls to be enabled. When they are, it is a slab-out-of-bounds read under KASAN and the bytes reach dmesg. Bound both dumps by the number of bytes actually received. That is in bounds by construction and also stops the dump printing stale bytes left over from an earlier transfer. The matching dumps on the two OUT paths are left alone: they use lengths the driver itself just wrote, which the size checks above them already bound. Found by code review. The out-of-bounds read was reproduced under AddressSanitizer with a userspace model of the two dev_dbg() call sites and of hex_string()'s field-width handling; it has not been exercised on hardware or on dummy_hcd. Fixes: 121a0f839dbb ("usb: misc: Add Intel USBIO bridge driver") Cc: stable@vger.kernel.org Assisted-by: Claude:claude-opus-5 asan Signed-off-by: HE WEI (ギカク) --- --- a/drivers/usb/misc/usbio.c +++ b/drivers/usb/misc/usbio.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -141,7 +142,7 @@ struct usbio_ctrl_packet *cpkt; unsigned int pipe; u16 cpkt_len; - int ret; + int dbg_len, ret; lockdep_assert_held(&usbio->ctrl_mutex); @@ -181,8 +182,15 @@ cpkt_len = sizeof(*cpkt) + ibuf_len; ret = usb_control_msg(usbio->udev, pipe, 0, request | USB_DIR_IN, 0, 0, cpkt, cpkt_len, USBIO_CTRLXFER_TIMEOUT); + /* + * cpkt->len has just been written by the device and is not validated + * until below, while %*phN dereferences up to 64 bytes of whatever + * field width it is handed. Bound the dump by what was received. + */ + dbg_len = (ret > (int)sizeof(*cpkt)) ? + min_t(int, cpkt->len, ret - (int)sizeof(*cpkt)) : 0; dev_dbg(usbio->dev, "control in %d hdr %*phN data %*phN\n", ret, - (int)sizeof(*cpkt), cpkt, (int)cpkt->len, cpkt->data); + (int)sizeof(*cpkt), cpkt, dbg_len, cpkt->data); if (ret < sizeof(*cpkt)) { dev_err(usbio->dev, "USB control in failed: %d\n", ret); @@ -258,7 +266,7 @@ struct usbio_client *client = adev_to_client(adev); struct usbio_device *usbio = client->bridge; struct usbio_bulk_packet *bpkt; - int ret, act = 0; + int ret, act = 0, dbg_len; u16 bpkt_len; lockdep_assert_held(&client->mutex); @@ -314,8 +322,14 @@ act = usbio->rxdat_len; bpkt = usbio->rxbuf; bpkt_len = le16_to_cpu(bpkt->len); + /* + * Same as in usbio_ctrl_msg(): bpkt_len is device supplied and is only + * validated below, so bound the dump by what was received. + */ + dbg_len = (act > (int)sizeof(*bpkt)) ? + min_t(int, bpkt_len, act - (int)sizeof(*bpkt)) : 0; dev_dbg(usbio->dev, "bulk in %d hdr %*phN data %*phN\n", act, - (int)sizeof(*bpkt), bpkt, bpkt_len, bpkt->data); + (int)sizeof(*bpkt), bpkt, dbg_len, bpkt->data); /* * Unsupported bulk commands get only an usbio_packet_header with -- 2.51.0