6.19.14-rc1 review
Subsystems (4)
Greg Kroah-Hartman
maintainerPATCH 164/220 usb: typec: fusb302: Switch to threaded IRQ handler
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alexey Charkov <[email protected]>
commit 6b9db53197094f38a18797495df2e3c758ec51dc upstream.
FUSB302 fails to probe with -EINVAL if its interrupt line is connected via an I2C GPIO expander, such as TI TCA6416.
Switch the interrupt handler to a threaded one, which also works behind such GPIO expanders.
--- drivers/usb/typec/tcpm/fusb302.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/usb/typec/tcpm/fusb302.c +3 -2
@@ -1755,8 +1755,9 @@ static int fusb302_probe(struct i2c_clie goto destroy_workqueue; } - ret =request_irq (chip->gpio_int_n_irq, fusb302_irq_intn, -IRQF_TRIGGER_LOW ,"fsc_interrupt_int_n" , chip); + ret =request_threaded_irq (chip->gpio_int_n_irq,NULL , fusb302_irq_intn, +IRQF_ONESHOT |IRQF_TRIGGER_LOW , +"fsc_interrupt_int_n" , chip);if (ret <0 ) {dev_err (dev,"cannot request IRQ for GPIO Int_N, ret=%d" , ret); goto tcpm_unregister_port;
Greg Kroah-Hartman
maintainerPATCH 165/220 usb: storage: Expand range of matched versions for VL817 quirks entry
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Daniel Brát <[email protected]>
commit 609865ab3d5d803556f628e221ecd3d06aed9f30 upstream.
Expands range of matched bcdDevice values for the VL817 quirk entry. This is based on experience with Axagon EE35-GTR rev1 3.5" HDD enclosure, which reports its bcdDevice as 0x0843, but presumably other vendors using this IC in their products may set it to any other value.
--- drivers/usb/storage/unusual_devs.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
drivers/usb/storage/unusual_devs.h +4 -3
@@ -2350,10 +2350,11 @@ UNUSUAL_DEV( 0x2027, 0xa001, 0x0000, 0x US_FL_SCM_MULT_TARG ),/* -* Reported by DocMAX <[email protected]> -* and Thomas Weißschuh <[email protected]> +* Reported by DocMAX <[email protected]>, +* Thomas Weißschuh <[email protected]> +* and Daniel Brát <[email protected]> */ -UNUSUAL_DEV( 0x2109, 0x0715, 0x9999, 0x9999, +UNUSUAL_DEV( 0x2109, 0x0715, 0x0000, 0x9999, "VIA Labs, Inc.", "VL817 SATA Bridge", USB_SC_DEVICE, USB_PR_DEVICE, NULL,
Greg Kroah-Hartman
maintainerPATCH 166/220 USB: cdc-acm: Add quirks for Yoga Book 9 14IAH10 INGENIC touchscreen
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dave Carey <[email protected]>
commit f58752ebcb35e156c85cd1a82d6579c7af3b9023 upstream.
The Lenovo Yoga Book 9 14IAH10 (83KJ) has a composite USB device (17EF:6161) that controls both touchscreens via a CDC ACM interface. Interface 0 is a standard CDC ACM control interface, but interface 1 (the data interface) incorrectly declares vendor-specific class (0xFF) instead of USB_CLASS_CDC_DATA. cdc-acm rejects the device at probe with -EINVAL, leaving interface 0 unbound and EP 0x82 never polled.
With no consumer polling EP 0x82, the firmware's watchdog fires every ~20 seconds and resets the USB bus, producing a continuous disconnect/ reconnect loop that prevents the touchscreens from ever initialising.
Add two new quirk flags:
VENDOR_CLASS_DATA_IFACE: Bypasses the bInterfaceClass check in acm_probe() that would otherwise reject the vendor-class data interface with -EINVAL.
ALWAYS_POLL_CTRL: Submits the notification URB at probe() rather than waiting for a TTY open. This keeps EP 0x82 polled at all times, permanently suppressing the firmware watchdog. The URB is resubmitted after port_shutdown() and on system resume. SET_CONTROL_LINE_STATE (DTR|RTS) is sent at probe and after port_shutdown() to complete firmware handshake.
Note: the firmware performs exactly 4 USB connect/disconnect cycles (~19 s each) on every cold boot before stabilising. This is a fixed firmware property; touch is available ~75-80 s after power-on.
--- drivers/usb/class/cdc-acm.c | 53 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 46 insertions(+), 7 deletions(-)
drivers/usb/class/cdc-acm.c +46 -7
@@ -114,6 +114,8 @@ static int acm_ctrl_msg(struct acm *acm,int retval; retval =usb_autopm_get_interface (acm->control); +#define VENDOR_CLASS_DATA_IFACE BIT(9)/* data interface uses vendor-specific class */ +#define ALWAYS_POLL_CTRL BIT(10)/* keep ctrl URB active even without an open TTY */ if (retval)return retval;
@@ -710,12 +712,14 @@ static int acm_port_activate(struct tty_set_bit (TTY_NO_WRITE_SPLIT , &tty->flags); acm->control->needs_remote_wakeup =1 ; - acm->ctrlurb->dev = acm->dev; - retval =usb_submit_urb (acm->ctrlurb,GFP_KERNEL ); -if (retval) { -dev_err (&acm->control->dev, -"%s - usb_submit_urb(ctrl irq) failed\n" , __func__); - goto error_submit_urb; +if (!(acm->quirks &ALWAYS_POLL_CTRL )) { + acm->ctrlurb->dev = acm->dev; + retval =usb_submit_urb (acm->ctrlurb,GFP_KERNEL ); +if (retval) { +dev_err (&acm->control->dev, +"%s - usb_submit_urb(ctrl irq) failed\n" , __func__); + goto error_submit_urb; + } }acm_tty_set_termios (tty,NULL );
@@ -788,6 +792,14 @@ static void acm_port_shutdown(struct ttyacm_unpoison_urbs (acm); +if (acm->quirks &ALWAYS_POLL_CTRL ) { + acm->ctrlurb->dev = acm->dev; +if (usb_submit_urb (acm->ctrlurb,GFP_KERNEL )) +dev_dbg (&acm->control->dev, +"ctrl polling restart failed after port close\n" ); +/* port_shutdown() cleared DTR/RTS; restore them */ +acm_set_control (acm,USB_CDC_CTRL_DTR |USB_CDC_CTRL_RTS ); + } }static void acm_tty_cleanup (struct tty_struct *tty)
@@ -1328,6 +1340,9 @@ skip_normal_probe:dev_dbg (&intf->dev,"Your device has switched interfaces.\n" );swap (control_interface, data_interface); + }else if (quirks &VENDOR_CLASS_DATA_IFACE ) { +dev_dbg (&intf->dev, +"Vendor-specific data interface class, continuing.\n" ); }else {return -EINVAL ; }
@@ -1522,6 +1537,9 @@ skip_countries: acm->line.bDataBits =8 ;acm_set_line (acm, &acm->line); +if (quirks &ALWAYS_POLL_CTRL ) +acm_set_control (acm,USB_CDC_CTRL_DTR |USB_CDC_CTRL_RTS ); +if (!acm->combined_interfaces) { rv =usb_driver_claim_interface (&acm_driver, data_interface, acm);if (rv)
@@ -1543,6 +1561,13 @@ skip_countries:dev_info (&intf->dev,"ttyACM%d: USB ACM device\n" , minor); +if (acm->quirks &ALWAYS_POLL_CTRL ) { + acm->ctrlurb->dev = acm->dev; +if (usb_submit_urb (acm->ctrlurb,GFP_KERNEL )) +dev_warn (&intf->dev, +"failed to start persistent ctrl polling\n" ); + } +return 0 ; err_release_data_interface:
@@ -1669,7 +1694,7 @@ static int acm_resume(struct usb_interfaacm_unpoison_urbs (acm); -if (tty_port_initialized (&acm->port)) { +if (tty_port_initialized (&acm->port) || (acm->quirks &ALWAYS_POLL_CTRL )) { rv =usb_submit_urb (acm->ctrlurb,GFP_ATOMIC );for (;;) {
@@ -2016,6 +2041,20 @@ static const struct usb_device_id acm_id/* CH343 supports CAP_BRK, but doesn't advertise it */ { USB_DEVICE(0x1a86, 0x55d3), .driver_info = MISSING_CAP_BRK, }, + /* + * Lenovo Yoga Book 9 14IAH10 (83KJ) — INGENIC 17EF:6161 touchscreen + * composite device. The CDC ACM control interface (0) uses a standard + * Union descriptor, but the data interface (1) is declared as vendor- + * specific class (0xff) with no CDC data descriptors, so cdc-acm would + * normally reject it. The firmware also requires continuous polling of + * the notification endpoint (EP 0x82) to suppress a 20-second watchdog + * reset; ALWAYS_POLL_CTRL keeps the ctrlurb active even when no TTY is + * open. Match only the control interface by class to avoid probing the + * vendor-specific data interface. + */ + { USB_DEVICE_INTERFACE_CLASS(0x17ef, 0x6161, USB_CLASS_COMM), + .driver_info = VENDOR_CLASS_DATA_IFACE | ALWAYS_POLL_CTRL }, + /* control interfaces without any protocol set */ { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, USB_CDC_PROTO_NONE) },
Greg Kroah-Hartman
maintainerPATCH 167/220 usb: gadget: f_hid: dont call cdev_init while cdev in use
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Zimmermann <[email protected]>
commit 81ebd43cc0d6d106ce7b6ccbf7b5e40ca7f5503d upstream.
When calling unbind, then bind again, cdev_init reinitialized the cdev, even though there may still be references to it. That's the case when the /dev/hidg* device is still opened. This obviously unsafe behavior like oopes.
This fixes this by using cdev_alloc to put the cdev on the heap. That way, we can simply allocate a new one in hidg_bind.
--- drivers/usb/gadget/function/f_hid.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-)
drivers/usb/gadget/function/f_hid.c +10 -5
@@ -106,7 +106,7 @@ struct f_hidg {struct list_head report_list;struct device dev; -struct cdev cdev; +struct cdev *cdev;struct usb_function func;struct usb_ep *in_ep;
@@ -749,8 +749,9 @@ static int f_hidg_release(struct inode *static int f_hidg_open (struct inode *inode,struct file *fd) { +struct kobject *parent = inode->i_cdev->kobj.parent;struct f_hidg *hidg = - container_of(inode->i_cdev, struct f_hidg, cdev); + container_of(parent, struct f_hidg, dev.kobj); fd->private_data = hidg;
@@ -1276,8 +1277,12 @@ static int hidg_bind(struct usb_configur }/* create char device */ -cdev_init (&hidg->cdev, &f_hidg_fops); - status =cdev_device_add (&hidg->cdev, &hidg->dev); + hidg->cdev =cdev_alloc (); +if (!hidg->cdev) + goto fail_free_all; + hidg->cdev->ops = &f_hidg_fops; + + status =cdev_device_add (hidg->cdev, &hidg->dev);if (status) goto fail_free_all;
@@ -1579,7 +1584,7 @@ static void hidg_unbind(struct usb_confi {struct f_hidg *hidg =func_to_hidg (f); -cdev_device_del (&hidg->cdev, &hidg->dev); +cdev_device_del (hidg->cdev, &hidg->dev);destroy_workqueue (hidg->workqueue);usb_free_all_descriptors (f); }
Greg Kroah-Hartman
maintainerPATCH 168/220 usb: port: add delay after usb_hub_set_port_power()
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xu Yang <[email protected]>
commit b84cc80610a8ce036deb987f056ce3196ead7f1e upstream.
When a port is disabled, an attached device will be disconnected. This causes a port-status-change event, which will race with hub autosuspend (if the disabled port was the only connected port on its hub), causing an immediate resume and a second autosuspend. Both of these can be avoided by adding a short delay after the call to usb_hub_set_port_power().
Below log shows what is happening:
$ echo 1 > usb1-port1/disable [ 37.958239] usb 1-1: USB disconnect, device number 2 [ 37.964101] usb 1-1: unregistering device [ 37.970070] hub 1-0:1.0: hub_suspend [ 37.971305] hub 1-0:1.0: state 7 ports 1 chg 0000 evt 0002 [ 37.974412] usb usb1: bus auto-suspend, wakeup 1 [ 37.988175] usb usb1: suspend raced with wakeup event <--- [ 37.993947] usb usb1: usb auto-resume [ 37.998401] hub 1-0:1.0: hub_resume [ 38.105688] usb usb1-port1: status 0000, change 0000, 12 Mb/s [ 38.112399] hub 1-0:1.0: state 7 ports 1 chg 0000 evt 0000 [ 38.118645] hub 1-0:1.0: hub_suspend [ 38.122963] usb usb1: bus auto-suspend, wakeup 1 [ 38.200368] usb usb1: usb wakeup-resume [ 38.204982] usb usb1: usb auto-resume [ 38.209376] hub 1-0:1.0: hub_resume [ 38.213676] usb usb1-port1: status 0101 change 0001 [ 38.321552] hub 1-0:1.0: state 7 ports 1 chg 0002 evt 0000 [ 38.327978] usb usb1-port1: status 0101, change 0000, 12 Mb/s [ 38.457429] usb 1-1: new high-speed USB device number 3 using ci_hdrc
Then, port change bit will be fixed to the final state and usb_clear_port_feature() can correctly clear it after this period. This will also avoid usb runtime suspend routine to run because usb_autopm_put_interface() not run yet.
--- drivers/usb/core/port.c | 1 + 1 file changed, 1 insertion(+)
drivers/usb/core/port.c +1 -0
@@ -141,6 +141,7 @@ static ssize_t disable_store(struct deviusb_disconnect (&port_dev->child); rc =usb_hub_set_port_power (hdev, hub, port1, !disabled); +msleep (2 *hub_power_on_good_delay (hub));if (disabled) {usb_clear_port_feature (hdev, port1,USB_PORT_FEAT_C_CONNECTION );
Greg Kroah-Hartman
maintainerPATCH 169/220 fbdev: udlfb: avoid divide-by-zero on FBIOPUT_VSCREENINFO
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Greg Kroah-Hartman <[email protected]>
commit a31e4518bec70333a0a98f2946a12b53b45fe5b9 upstream.
Much like commit 19f953e74356 ("fbdev: fb_pm2fb: Avoid potential divide by zero error"), we also need to prevent that same crash from happening in the udlfb driver as it uses pixclock directly when dividing, which will crash.
--- drivers/video/fbdev/udlfb.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/video/fbdev/udlfb.c +3 -0
@@ -1018,6 +1018,9 @@ static int dlfb_ops_check_var(struct fb_struct fb_videomode mode;struct dlfb_data *dlfb = info->par; +if (!var->pixclock) +return -EINVAL ; +/* set device-specific elements of var unrelated to mode */ dlfb_var_color_format (var);
Greg Kroah-Hartman
maintainerPATCH 170/220 scripts/gdb/symbols: handle module path parameters
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Benjamin Berg <[email protected]>
commit 8e4513303b8726e4434f718ab39749cbb4c142b1 upstream.
commit 581ee79a2547 ("scripts/gdb/symbols: make BPF debug info available to GDB") added support to make BPF debug information available to GDB. However, the argument handling loop was slightly broken, causing it to fail if further modules were passed. Fix it to append these passed modules to the instance variable after expansion.
--- scripts/gdb/linux/symbols.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
scripts/gdb/linux/symbols.py +1 -1
@@ -298,7 +298,7 @@ are loaded as well.""" if p == "-bpf": monitor_bpf = True else: - p.append(os.path.abspath(os.path.expanduser(p))) + self.module_paths.append(os.path.abspath(os.path.expanduser(p))) self.module_paths.append(os.getcwd()) if self.breakpoint is not None:
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 171/220 scripts: generate_rust_analyzer.py: avoid FD leak
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tamir Duberstein <[email protected]>
commit 9b4744d8eda2824041064a5639ccbb079850914d upstream.
Use pathlib.Path.read_text() to avoid leaking file descriptors.
--- scripts/generate_rust_analyzer.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
scripts/generate_rust_analyzer.py +2 -1
@@ -190,9 +190,10 @@ def generate_crates(srctree, objtree, sy def is_root_crate(build_file, target): try: - return f"{target}.o" in open(build_file).read() + contents = build_file.read_text() except FileNotFoundError: return False + return f"{target}.o" in contents # Then, the rest outside of `rust/`. #
Greg Kroah-Hartman
maintainerPATCH 172/220 wifi: rtw88: fix device leak on probe failure
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <[email protected]>
commit bbb15e71156cd9f5e1869eee7207a06ea8e96c39 upstream.
Driver core holds a reference to the USB interface and its parent USB device while the interface is bound to a driver and there is no need to take additional references unless the structures are needed after disconnect.
This driver takes a reference to the USB device during probe but does not to release it on all probe errors (e.g. when descriptor parsing fails).
Drop the redundant device reference to fix the leak, reduce cargo culting, make it easier to spot drivers where an extra reference is needed, and reduce the risk of further memory leaks.
--- drivers/net/wireless/realtek/rtw88/usb.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/net/wireless/realtek/rtw88/usb.c +1 -2
@@ -1040,7 +1040,7 @@ static int rtw_usb_intf_init(struct rtw_ struct usb_interface *intf) {struct rtw_usb *rtwusb =rtw_get_usb_priv (rtwdev); -struct usb_device *udev =usb_get_dev (interface_to_usbdev (intf)); +struct usb_device *udev =interface_to_usbdev (intf);int ret; rtwusb->udev = udev;
@@ -1066,7 +1066,6 @@ static void rtw_usb_intf_deinit(struct r {struct rtw_usb *rtwusb =rtw_get_usb_priv (rtwdev); -usb_put_dev (rtwusb->udev);kfree (rtwusb->usb_data);usb_set_intfdata (intf,NULL ); }
Greg Kroah-Hartman
maintainerPATCH 173/220 staging: sm750fb: fix division by zero in ps_to_hz()
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Junrui Luo <[email protected]>
commit 75a1621e4f91310673c9acbcbb25c2a7ff821cd3 upstream.
ps_to_hz() is called from hw_sm750_crtc_set_mode() without validating that pixclock is non-zero. A zero pixclock passed via FBIOPUT_VSCREENINFO causes a division by zero.
Fix by rejecting zero pixclock in lynxfb_ops_check_var(), consistent with other framebuffer drivers.
--- drivers/staging/sm750fb/sm750.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/staging/sm750fb/sm750.c +3 -0
@@ -481,6 +481,9 @@ static int lynxfb_ops_check_var(struct fstruct lynxfb_crtc *crtc;resource_size_t request; +if (!var->pixclock) +return -EINVAL ; + ret =0 ; par = info->par; crtc = &par->crtc;
Greg Kroah-Hartman
maintainerPATCH 174/220 selftests/mm: hmm-tests: dont hardcode THP size to 2MB
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alistair Popple <[email protected]>
commit f9d7975c52c00b3685cf9a90a81023d17817d991 upstream.
Several HMM tests hardcode TWOMEG as the THP size. This is wrong on architectures where the PMD size is not 2MB such as arm64 with 64K base pages where THP is 512MB. Fix this by using read_pmd_pagesize() from vm_util instead.
While here also replace the custom file_read_ulong() helper used to parse the default hugetlbfs page size from /proc/meminfo with the existing default_huge_page_size() from vm_util.
--- tools/testing/selftests/mm/hmm-tests.c | 83 ++++++--------------------------- 1 file changed, 16 insertions(+), 67 deletions(-)
tools/testing/selftests/mm/hmm-tests.c +16 -67
@@ -34,6 +34,7 @@*/ #include <lib/test_hmm_uapi.h> #include <mm/gup_test.h> +#include <mm/vm_util.h> struct hmm_buffer {void *ptr;
@@ -548,7 +549,7 @@ TEST_F(hmm, anon_write_child)for (migrate =0 ; migrate <2 ; ++migrate) {for (use_thp =0 ; use_thp <2 ; ++use_thp) { - npages =ALIGN (use_thp ?TWOMEG :HMM_BUFFER_SIZE , + npages =ALIGN (use_thp ?read_pmd_pagesize () :HMM_BUFFER_SIZE , self->page_size) >> self->page_shift;ASSERT_NE (npages,0 ); size = npages << self->page_shift;
@@ -728,7 +729,7 @@ TEST_F(hmm, anon_write_huge)int *ptr;int ret; - size =2 *TWOMEG ; + size =2 *read_pmd_pagesize (); buffer =malloc (sizeof (*buffer));ASSERT_NE (buffer,NULL );
@@ -744,7 +745,7 @@ TEST_F(hmm, anon_write_huge) buffer->fd, 0);ASSERT_NE (buffer->ptr,MAP_FAILED ); - size =TWOMEG ; + size /=2 ; npages = size >> self->page_shift; map = (void *)ALIGN ((uintptr_t )buffer->ptr, size); ret =madvise (map, size,MADV_HUGEPAGE );
@@ -771,54 +772,6 @@ TEST_F(hmm, anon_write_huge) }/* -* Read numeric data from raw and tagged kernel status files. Used to read -* /proc and /sys data (without a tag) and from /proc/meminfo (with a tag). -*/ -static long file_read_ulong (char *file,const char *tag) -{ -int fd; -char buf[2048 ]; -int len; -char *p, *q; -long val; - - fd =open (file,O_RDONLY ); -if (fd <0 ) { -/* Error opening the file */ -return -1 ; - } - - len =read (fd, buf,sizeof (buf)); -close (fd); -if (len <0 ) { -/* Error in reading the file */ -return -1 ; - } -if (len ==sizeof (buf)) { -/* Error file is too large */ -return -1 ; - } - buf[len] ='\0' ; - -/* Search for a tag if provided */ -if (tag) { - p =strstr (buf, tag); -if (!p) -return -1 ;/* looks like the line we want isn't there */ - p +=strlen (tag); - }else - p = buf; - - val =strtol (p, &q,0 ); -if (*q !=' ' ) { -/* Error parsing the file */ -return -1 ; - } - -return val; -} - -/* * Write huge TLBFS page. */ TEST_F (hmm, anon_write_hugetlbfs)
@@ -826,15 +779,13 @@ TEST_F(hmm, anon_write_hugetlbfs)struct hmm_buffer *buffer;unsigned long npages;unsigned long size; -unsigned long default_hsize; +unsigned long default_hsize =default_huge_page_size ();unsigned long i;int *ptr;int ret; - default_hsize =file_read_ulong ("/proc/meminfo" ,"Hugepagesize:" ); -if (default_hsize <0 || default_hsize*1024 < default_hsize) +if (!default_hsize)SKIP (return,"Huge page size could not be determined" ); - default_hsize = default_hsize*1024 ;/* KB to B */ size =ALIGN (TWOMEG , default_hsize); npages = size >> self->page_shift;
@@ -1606,7 +1557,7 @@ TEST_F(hmm, compound)struct hmm_buffer *buffer;unsigned long npages;unsigned long size; -unsigned long default_hsize; +unsigned long default_hsize =default_huge_page_size ();int *ptr;unsigned char *m;int ret;
@@ -1614,10 +1565,8 @@ TEST_F(hmm, compound)/* Skip test if we can't allocate a hugetlbfs page. */ - default_hsize =file_read_ulong ("/proc/meminfo" ,"Hugepagesize:" ); -if (default_hsize <0 || default_hsize*1024 < default_hsize) +if (!default_hsize)SKIP (return,"Huge page size could not be determined" ); - default_hsize = default_hsize*1024 ;/* KB to B */ size =ALIGN (TWOMEG , default_hsize); npages = size >> self->page_shift;
@@ -2106,7 +2055,7 @@ TEST_F(hmm, migrate_anon_huge_empty)int *ptr;int ret; - size =TWOMEG ; + size =read_pmd_pagesize (); buffer =malloc (sizeof (*buffer));ASSERT_NE (buffer,NULL );
@@ -2158,7 +2107,7 @@ TEST_F(hmm, migrate_anon_huge_zero)int ret;int val; - size =TWOMEG ; + size =read_pmd_pagesize (); buffer =malloc (sizeof (*buffer));ASSERT_NE (buffer,NULL );
@@ -2221,7 +2170,7 @@ TEST_F(hmm, migrate_anon_huge_free)int *ptr;int ret; - size =TWOMEG ; + size =read_pmd_pagesize (); buffer =malloc (sizeof (*buffer));ASSERT_NE (buffer,NULL );
@@ -2280,7 +2229,7 @@ TEST_F(hmm, migrate_anon_huge_fault)int *ptr;int ret; - size =TWOMEG ; + size =read_pmd_pagesize (); buffer =malloc (sizeof (*buffer));ASSERT_NE (buffer,NULL );
@@ -2332,7 +2281,7 @@ TEST_F(hmm, migrate_partial_unmap_fault) {struct hmm_buffer *buffer;unsigned long npages; -unsigned long size =TWOMEG ; +unsigned long size =read_pmd_pagesize ();unsigned long i;void *old_ptr;void *map;
@@ -2398,7 +2347,7 @@ TEST_F(hmm, migrate_remap_fault) {struct hmm_buffer *buffer;unsigned long npages; -unsigned long size =TWOMEG ; +unsigned long size =read_pmd_pagesize ();unsigned long i;void *old_ptr, *new_ptr =NULL ;void *map;
@@ -2498,7 +2447,7 @@ TEST_F(hmm, migrate_anon_huge_err)int *ptr;int ret; - size =TWOMEG ; + size =read_pmd_pagesize (); buffer =malloc (sizeof (*buffer));ASSERT_NE (buffer,NULL );
@@ -2593,7 +2542,7 @@ TEST_F(hmm, migrate_anon_huge_zero_err)int *ptr;int ret; - size =TWOMEG ; + size =read_pmd_pagesize (); buffer =malloc (sizeof (*buffer));ASSERT_NE (buffer,NULL );
Greg Kroah-Hartman
maintainerPATCH 175/220 USB: serial: option: add Telit Cinterion FN990A MBIM composition
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fabio Porcedda <[email protected]>
commit f8cc59ecc22841be5deb07b549c0c6a2657cd5f9 upstream.
Add the following Telit Cinterion FN990A MBIM composition:
0x1074: MBIM + tty (AT/NMEA) + tty (AT) + tty (AT) + tty (diag) +
DPL (Data Packet Logging) + adb
T: Bus=01 Lev=01 Prnt=04 Port=06 Cnt=01 Dev#= 7 Spd=480 MxCh= 0 D: Ver= 2.10 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=1bc7 ProdID=1074 Rev=05.04 S: Manufacturer=Telit Wireless Solutions S: Product=FN990 S: SerialNumber=70628d0c C: #Ifs= 8 Cfg#= 1 Atr=e0 MxPwr=500mA I: If#= 0 Alt= 0 #EPs= 1 Cls=02(commc) Sub=0e Prot=00 Driver=cdc_mbim E: Ad=81(I) Atr=03(Int.) MxPS= 64 Ivl=32ms I: If#= 1 Alt= 1 #EPs= 2 Cls=0a(data ) Sub=00 Prot=02 Driver=cdc_mbim E: Ad=0f(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=8e(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I: If#= 2 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=60 Driver=option E: Ad=01(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=82(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=83(I) Atr=03(Int.) MxPS= 10 Ivl=32ms I: If#= 3 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=40 Driver=option E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=84(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=85(I) Atr=03(Int.) MxPS= 10 Ivl=32ms I: If#= 4 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=40 Driver=option E: Ad=03(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=86(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=87(I) Atr=03(Int.) MxPS= 10 Ivl=32ms I: If#= 5 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=30 Driver=option E: Ad=04(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=88(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I: If#= 6 Alt= 0 #EPs= 1 Cls=ff(vend.) Sub=ff Prot=80 Driver=(none) E: Ad=8f(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I: If#= 7 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=42 Prot=01 Driver=(none) E: Ad=05(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=89(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
--- drivers/usb/serial/option.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/usb/serial/option.c +2 -0
@@ -1383,6 +1383,8 @@ static const struct usb_device_id option .driver_info = NCTRL(2) | RSVD(3) }, { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1073, 0xff), /* Telit FN990A (ECM) */ .driver_info = NCTRL(0) | RSVD(1) }, + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1074, 0xff), /* Telit FN990A (MBIM) */ + .driver_info = NCTRL(5) | RSVD(6) | RSVD(7) }, { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1075, 0xff), /* Telit FN990A (PCIe) */ .driver_info = RSVD(0) }, { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1077, 0xff), /* Telit FN990A (rmnet + audio) */
Greg Kroah-Hartman
maintainerPATCH 176/220 Docs/admin-guide/mm/damon/reclaim: warn commit_inputs vs param updates race
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: SeongJae Park <[email protected]>
commit 0beba407d4585a15b0dc09f2064b5b3ddcb0e857 upstream.
Patch series "Docs/admin-guide/mm/damon: warn commit_inputs vs other params race".
Writing 'Y' to the commit_inputs parameter of DAMON_RECLAIM and DAMON_LRU_SORT, and writing other parameters before the commit_inputs request is completely processed can cause race conditions. While the consequence can be bad, the documentation is not clearly describing that. Add clear warnings.
The issue was discovered [1,2] by sashiko.
This patch (of 2):
DAMON_RECLAIM handles commit_inputs request inside kdamond thread, reading the module parameters. If the user updates the module parameters while the kdamond thread is reading those, races can happen. To avoid this, the commit_inputs parameter shows whether it is still in the progress, assuming users wouldn't update parameters in the middle of the work. Some users might ignore that. Add a warning about the behavior.
The issue was discovered in [1] by sashiko.
--- Documentation/admin-guide/mm/damon/reclaim.rst | 4 ++++ 1 file changed, 4 insertions(+)
Documentation/admin-guide/mm/damon/reclaim.rst +4 -0
@@ -71,6 +71,10 @@ of parametrs except ``enabled`` again. parameter is set as ``N``. If invalid parameters are found while the re-reading, DAMON_RECLAIM will be disabled. +Once ``Y`` is written to this parameter, the user must not write to any +parameters until reading ``commit_inputs`` again returns ``N``. If users +violate this rule, the kernel may exhibit undefined behavior. + min_age -------
Greg Kroah-Hartman
maintainerPATCH 177/220 ALSA: ctxfi: Limit PTP to a single page
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Harin Lee <[email protected]>
commit e9418da50d9e5c496c22fe392e4ad74c038a94eb upstream.
Commit 391e69143d0a increased CT_PTP_NUM from 1 to 4 to support 256 playback streams, but the additional pages are not used by the card correctly. The CT20K2 hardware already has multiple VMEM_PTPAL registers, but using them separately would require refactoring the entire virtual memory allocation logic.
ct_vm_map() always uses PTEs in vm->ptp[0].area regardless of CT_PTP_NUM. On AMD64 systems, a single PTP covers 512 PTEs (2M). When aggregate memory allocations exceed this limit, ct_vm_map() tries to access beyond the allocated space and causes a page fault:
BUG: unable to handle page fault for address: ffffd4ae8a10a000 Oops: Oops: 0002 [#1] SMP PTI RIP: 0010:ct_vm_map+0x17c/0x280 [snd_ctxfi] Call Trace: atc_pcm_playback_prepare+0x225/0x3b0 ct_pcm_playback_prepare+0x38/0x60 snd_pcm_do_prepare+0x2f/0x50 snd_pcm_action_single+0x36/0x90 snd_pcm_action_nonatomic+0xbf/0xd0 snd_pcm_ioctl+0x28/0x40 __x64_sys_ioctl+0x97/0xe0 do_syscall_64+0x81/0x610 entry_SYSCALL_64_after_hwframe+0x76/0x7e
Revert CT_PTP_NUM to 1. The 256 SRC_RESOURCE_NUM and playback_count remain unchanged.
--- sound/pci/ctxfi/ctvmem.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
sound/pci/ctxfi/ctvmem.h +1 -1
@@ -15,7 +15,7 @@#ifndef CTVMEM_H #define CTVMEM_H -#define CT_PTP_NUM 4/* num of device page table pages */ +#define CT_PTP_NUM 1/* num of device page table pages */ #include <linux/mutex.h> #include <linux/list.h>
Greg Kroah-Hartman
maintainerPATCH 178/220 dcache: Limit the minimal number of bucket to two
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhihao Cheng <[email protected]>
commit f08fe8891c3eeb63b73f9f1f6d97aa629c821579 upstream.
There is an OOB read problem on dentry_hashtable when user sets 'dhash_entries=1':
BUG: unable to handle page fault for address: ffff888b30b774b0
#PF: supervisor read access in kernel mode
#PF: error_code(0x0000) - not-present page
Oops: Oops: 0000 [#1] SMP PTI
RIP: 0010:__d_lookup+0x56/0x120
Call Trace:
d_lookup.cold+0x16/0x5d
lookup_dcache+0x27/0xf0
lookup_one_qstr_excl+0x2a/0x180
start_dirop+0x55/0xa0
simple_start_creating+0x8d/0xa0
debugfs_start_creating+0x8c/0x180
debugfs_create_dir+0x1d/0x1c0
pinctrl_init+0x6d/0x140
do_one_initcall+0x6d/0x3d0
kernel_init_freeable+0x39f/0x460
kernel_init+0x2a/0x260There will be only one bucket in dentry_hashtable when dhash_entries is set as one, and d_hash_shift is calculated as 32 by dcache_init(). Then, following process will access more than one buckets(which memory region is not allocated) in dentry_hashtable:
d_lookup
b = d_hash(hash)
dentry_hashtable + ((u32)hashlen >> d_hash_shift)
// The C standard defines the behavior of right shift amounts
// exceeding the bit width of the operand as undefined. The
// result of '(u32)hashlen >> d_hash_shift' becomes 'hashlen',
// so 'b' will point to an unallocated memory region.
hlist_bl_for_each_entry_rcu(b)
hlist_bl_first_rcu(head)
h->first // read OOB!Fix it by limiting the minimal number of dentry_hashtable bucket to two, so that 'd_hash_shift' won't exceeds the bit width of type u32.
--- fs/dcache.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
fs/dcache.c +2 -2
@@ -3260,7 +3260,7 @@ static void __init dcache_init_early(voiHASH_EARLY |HASH_ZERO , &d_hash_shift,NULL , -0 , +2 , 0); d_hash_shift =32 - d_hash_shift;
@@ -3292,7 +3292,7 @@ static void __init dcache_init(void)HASH_ZERO , &d_hash_shift,NULL , -0 , +2 , 0); d_hash_shift =32 - d_hash_shift;
Greg Kroah-Hartman
maintainerPATCH 179/220 vfio/xe: Reorganize the init to decouple migration from reset
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michał Winiarski <[email protected]>
commit 1b81ed612e12ea9df8c5cb6f0ddd4419fd0b8ac8 upstream.
Attempting to issue reset on VF devices that don't support migration leads to the following:
BUG: unable to handle page fault for address: 00000000000011f8 #PF: supervisor read access in kernel mode #PF: error_code(0x0000) - not-present page PGD 0 P4D 0 Oops: Oops: 0000 [#1] SMP NOPTI CPU: 2 UID: 0 PID: 7443 Comm: xe_sriov_flr Tainted: G S U 7.0.0-rc1-lgci-xe-xe-4588-cec43d5c2696af219-nodebug+ #1 PREEMPT(lazy) Tainted: [S]=CPU_OUT_OF_SPEC, [U]=USER Hardware name: Intel Corporation Alder Lake Client Platform/AlderLake-P DDR4 RVP, BIOS RPLPFWI1.R00.4035.A00.2301200723 01/20/2023 RIP: 0010:xe_sriov_vfio_wait_flr_done+0xc/0x80 [xe] Code: ff c3 cc cc cc cc 0f 1f 84 00 00 00 00 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 0f 1f 44 00 00 55 48 89 e5 41 54 53 <83> bf f8 11 00 00 02 75 61 41 89 f4 85 f6 74 52 48 8b 47 08 48 89 RSP: 0018:ffffc9000f7c39b8 EFLAGS: 00010202 RAX: ffffffffa04d8660 RBX: ffff88813e3e4000 RCX: 0000000000000000 RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000 RBP: ffffc9000f7c39c8 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000000 R12: ffff888101a48800 R13: ffff88813e3e4150 R14: ffff888130d0d008 R15: ffff88813e3e40d0 FS: 00007877d3d0d940(0000) GS:ffff88890b6d3000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00000000000011f8 CR3: 000000015a762000 CR4: 0000000000f52ef0 PKRU: 55555554 Call Trace: <TASK> xe_vfio_pci_reset_done+0x49/0x120 [xe_vfio_pci] pci_dev_restore+0x3b/0x80 pci_reset_function+0x109/0x140 reset_store+0x5c/0xb0 dev_attr_store+0x17/0x40 sysfs_kf_write+0x72/0x90 kernfs_fop_write_iter+0x161/0x1f0 vfs_write+0x261/0x440 ksys_write+0x69/0xf0 __x64_sys_write+0x19/0x30 x64_sys_call+0x259/0x26e0 do_syscall_64+0xcb/0x1500 ? __fput+0x1a2/0x2d0 ? fput_close_sync+0x3d/0xa0 ? __x64_sys_close+0x3e/0x90 ? x64_sys_call+0x1b7c/0x26e0 ? do_syscall_64+0x109/0x1500 ? __task_pid_nr_ns+0x68/0x100 ? __do_sys_getpid+0x1d/0x30 ? x64_sys_call+0x10b5/0x26e0 ? do_syscall_64+0x109/0x1500 ? putname+0x41/0x90 ? do_faccessat+0x1e8/0x300 ? __x64_sys_access+0x1c/0x30 ? x64_sys_call+0x1822/0x26e0 ? do_syscall_64+0x109/0x1500 ? tick_program_event+0x43/0xa0 ? hrtimer_interrupt+0x126/0x260 ? irqentry_exit+0xb2/0x710 entry_SYSCALL_64_after_hwframe+0x76/0x7e RIP: 0033:0x7877d5f1c5a4 Code: c7 00 16 00 00 00 b8 ff ff ff ff c3 66 2e 0f 1f 84 00 00 00 00 00 f3 0f 1e fa 80 3d a5 ea 0e 00 00 74 13 b8 01 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 54 c3 0f 1f 00 55 48 89 e5 48 83 ec 20 48 89 RSP: 002b:00007fff48e5f908 EFLAGS: 00000202 ORIG_RAX: 0000000000000001 RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007877d5f1c5a4 RDX: 0000000000000001 RSI: 00007877d621b0c9 RDI: 0000000000000009 RBP: 0000000000000001 R08: 00005fb49113b010 R09: 0000000000000007 R10: 0000000000000000 R11: 0000000000000202 R12: 00007877d621b0c9 R13: 0000000000000009 R14: 00007fff48e5fac0 R15: 00007fff48e5fac0 </TASK>
This is caused by the fact that some of the xe_vfio_pci_core_device members needed for handling reset are only initialized as part of migration init.
Fix the problem by reorganizing the code to decouple VF init from migration init.
--- drivers/vfio/pci/xe/main.c | 43 ++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 18 deletions(-)
drivers/vfio/pci/xe/main.c +25 -18
@@ -454,39 +454,46 @@ static const struct vfio_migration_ops xe_vfio_pci_migration_ops = {static void xe_vfio_pci_migration_init (struct xe_vfio_pci_core_device *xe_vdev) {struct vfio_device *core_vdev = &xe_vdev->core_device.vdev; -struct pci_dev *pdev =to_pci_dev (core_vdev->dev); -struct xe_device *xe =xe_sriov_vfio_get_pf (pdev); -if (!xe) +if (!xe_sriov_vfio_migration_supported (xe_vdev->xe))return ; -if (!xe_sriov_vfio_migration_supported (xe)) -return ; - -mutex_init (&xe_vdev->state_mutex); -spin_lock_init (&xe_vdev->reset_lock); - -/* PF internal control uses vfid index starting from 1 */ - xe_vdev->vfid =pci_iov_vf_id (pdev) +1 ; - xe_vdev->xe = xe; core_vdev->migration_flags =VFIO_MIGRATION_STOP_COPY |VFIO_MIGRATION_P2P ; core_vdev->mig_ops = &xe_vfio_pci_migration_ops; } -static void xe_vfio_pci_migration_fini (struct xe_vfio_pci_core_device *xe_vdev) +static int xe_vfio_pci_vf_init (struct xe_vfio_pci_core_device *xe_vdev) { -if (!xe_vdev->vfid) -return ; +struct vfio_device *core_vdev = &xe_vdev->core_device.vdev; +struct pci_dev *pdev =to_pci_dev (core_vdev->dev); +struct xe_device *xe =xe_sriov_vfio_get_pf (pdev); -mutex_destroy (&xe_vdev->state_mutex); +if (!pdev->is_virtfn) +return 0 ; +if (!xe) +return -ENODEV ; + xe_vdev->xe = xe; + +/* PF internal control uses vfid index starting from 1 */ + xe_vdev->vfid =pci_iov_vf_id (pdev) +1 ; + +xe_vfio_pci_migration_init (xe_vdev); + +return 0 ; }static int xe_vfio_pci_init_dev (struct vfio_device *core_vdev) {struct xe_vfio_pci_core_device *xe_vdev = container_of(core_vdev, struct xe_vfio_pci_core_device, core_device.vdev); +int ret; -xe_vfio_pci_migration_init (xe_vdev); +mutex_init (&xe_vdev->state_mutex); +spin_lock_init (&xe_vdev->reset_lock); + + ret =xe_vfio_pci_vf_init (xe_vdev); +if (ret) +return ret;return vfio_pci_core_init_dev (core_vdev); }
@@ -496,7 +503,7 @@ static void xe_vfio_pci_release_dev(struct vfio_device *core_vdev)struct xe_vfio_pci_core_device *xe_vdev = container_of(core_vdev, struct xe_vfio_pci_core_device, core_device.vdev); -xe_vfio_pci_migration_fini (xe_vdev); +mutex_destroy (&xe_vdev->state_mutex); }static const struct vfio_device_ops xe_vfio_pci_ops = {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 180/220 arm64: mm: Handle invalid large leaf mappings correctly
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ryan Roberts <[email protected]>
commit 15bfba1ad77fad8e45a37aae54b3c813b33fe27c upstream.
It has been possible for a long time to mark ptes in the linear map as invalid. This is done for secretmem, kfence, realm dma memory un/share, and others, by simply clearing the PTE_VALID bit. But until commit a166563e7ec37 ("arm64: mm: support large block mapping when rodata=full") large leaf mappings were never made invalid in this way.
It turns out various parts of the code base are not equipped to handle invalid large leaf mappings (in the way they are currently encoded) and I've observed a kernel panic while booting a realm guest on a BBML2_NOABORT system as a result:
[ 15.432706] software IO TLB: Memory encryption is active and system is using DMA bounce buffers [ 15.476896] Unable to handle kernel paging request at virtual address ffff000019600000 [ 15.513762] Mem abort info: [ 15.527245] ESR = 0x0000000096000046 [ 15.548553] EC = 0x25: DABT (current EL), IL = 32 bits [ 15.572146] SET = 0, FnV = 0 [ 15.592141] EA = 0, S1PTW = 0 [ 15.612694] FSC = 0x06: level 2 translation fault [ 15.640644] Data abort info: [ 15.661983] ISV = 0, ISS = 0x00000046, ISS2 = 0x00000000 [ 15.694875] CM = 0, WnR = 1, TnD = 0, TagAccess = 0 [ 15.723740] GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0 [ 15.755776] swapper pgtable: 4k pages, 48-bit VAs, pgdp=0000000081f3f000 [ 15.800410] [ffff000019600000] pgd=0000000000000000, p4d=180000009ffff403, pud=180000009fffe403, pmd=00e8000199600704 [ 15.855046] Internal error: Oops: 0000000096000046 [#1] SMP [ 15.886394] Modules linked in: [ 15.900029] CPU: 0 UID: 0 PID: 1 Comm: swapper/0 Not tainted 7.0.0-rc4-dirty #4 PREEMPT [ 15.935258] Hardware name: linux,dummy-virt (DT) [ 15.955612] pstate: 21400005 (nzCv daif +PAN -UAO -TCO +DIT -SSBS BTYPE=--) [ 15.986009] pc : __pi_memcpy_generic+0x128/0x22c [ 16.006163] lr : swiotlb_bounce+0xf4/0x158 [ 16.024145] sp : ffff80008000b8f0 [ 16.038896] x29: ffff80008000b8f0 x28: 0000000000000000 x27: 0000000000000000 [ 16.069953] x26: ffffb3976d261ba8 x25: 0000000000000000 x24: ffff000019600000 [ 16.100876] x23: 0000000000000001 x22: ffff0000043430d0 x21: 0000000000007ff0 [ 16.131946] x20: 0000000084570010 x19: 0000000000000000 x18: ffff00001ffe3fcc [ 16.163073] x17: 0000000000000000 x16: 00000000003fffff x15: 646e612065766974 [ 16.194131] x14: 0000000000000000 x13: 0000000000000000 x12: 0000000000000000 [ 16.225059] x11: 0000000000000000 x10: 0000000000000010 x9 : 0000000000000018 [ 16.256113] x8 : 0000000000000018 x7 : 0000000000000000 x6 : 0000000000000000 [ 16.287203] x5 : ffff000019607ff0 x4 : ffff000004578000 x3 : ffff000019600000 [ 16.318145] x2 : 0000000000007ff0 x1 : ffff000004570010 x0 : ffff000019600000 [ 16.349071] Call trace: [ 16.360143] __pi_memcpy_generic+0x128/0x22c (P) [ 16.380310] swiotlb_tbl_map_single+0x154/0x2b4 [ 16.400282] swiotlb_map+0x5c/0x228 [ 16.415984] dma_map_phys+0x244/0x2b8 [ 16.432199] dma_map_page_attrs+0x44/0x58 [ 16.449782] virtqueue_map_page_attrs+0x38/0x44 [ 16.469596] virtqueue_map_single_attrs+0xc0/0x130 [ 16.490509] virtnet_rq_alloc.isra.0+0xa4/0x1fc [ 16.510355] try_fill_recv+0x2a4/0x584 [ 16.526989] virtnet_open+0xd4/0x238 [ 16.542775] __dev_open+0x110/0x24c [ 16.558280] __dev_change_flags+0x194/0x20c [ 16.576879] netif_change_flags+0x24/0x6c [ 16.594489] dev_change_flags+0x48/0x7c [ 16.611462] ip_auto_config+0x258/0x1114 [ 16.628727] do_one_initcall+0x80/0x1c8 [ 16.645590] kernel_init_freeable+0x208/0x2f0 [ 16.664917] kernel_init+0x24/0x1e0 [ 16.680295] ret_from_fork+0x10/0x20 [ 16.696369] Code: 927cec03 cb0e0021 8b0e0042 a9411c26 (a900340c) [ 16.723106] ---[ end trace 0000000000000000 ]--- [ 16.752866] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 16.792556] Kernel Offset: 0x3396ea200000 from 0xffff800080000000 [ 16.818966] PHYS_OFFSET: 0xfff1000080000000 [ 16.837237] CPU features: 0x0000000,00060005,13e38581,957e772f [ 16.862904] Memory Limit: none [ 16.876526] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]---
This panic occurs because the swiotlb memory was previously shared to the host (__set_memory_enc_dec()), which involves transitioning the (large) leaf mappings to invalid, sharing to the host, then marking the mappings valid again. But pageattr_p[mu]d_entry() would only update the entry if it is a section mapping, since otherwise it concluded it must be a table entry so shouldn't be modified. But p[mu]d_sect() only returns true if the entry is valid. So the result was that the large leaf entry was made invalid in the first pass then ignored in the second pass. It remains invalid until the above code tries to access it and blows up.
The simple fix would be to update pageattr_pmd_entry() to use !pmd_table() instead of pmd_sect(). That would solve this problem.
But the ptdump code also suffers from a similar issue. It checks pmd_leaf() and doesn't call into the arch-specific note_page() machinery if it returns false. As a result of this, ptdump wasn't even able to show the invalid large leaf mappings; it looked like they were valid which made this super fun to debug. the ptdump code is core-mm and pmd_table() is arm64-specific so we can't use the same trick to solve that.
But we already support the concept of "present-invalid" for user space entries. And even better, pmd_leaf() will return true for a leaf mapping that is marked present-invalid. So let's just use that encoding for present-invalid kernel mappings too. Then we can use pmd_leaf() where we previously used pmd_sect() and everything is magically fixed.
Additionally, from inspection kernel_page_present() was broken in a similar way, so I'm also updating that to use pmd_leaf().
The transitional page tables component was also similarly broken; it creates a copy of the kernel page tables, making RO leaf mappings RW in the process. It also makes invalid (but-not-none) pte mappings valid. But it was not doing this for large leaf mappings. This could have resulted in crashes at kexec- or hibernate-time. This code is fixed to flip "present-invalid" mappings back to "present-valid" at all levels.
Finally, I have hardened split_pmd()/split_pud() so that if it is passed a "present-invalid" leaf, it will maintain that property in the split leaves, since I wasn't able to convince myself that it would only ever be called for "present-valid" leaves.
--- arch/arm64/include/asm/pgtable-prot.h | 2 + arch/arm64/include/asm/pgtable.h | 9 ++++-- arch/arm64/mm/mmu.c | 4 ++ arch/arm64/mm/pageattr.c | 50 +++++++++++++++++++--------------- arch/arm64/mm/trans_pgd.c | 42 ++++------------------------ 5 files changed, 48 insertions(+), 59 deletions(-)
arch/arm64/include/asm/pgtable-prot.h +2 -0
@@ -25,6 +25,8 @@*/ #define PTE_PRESENT_INVALID (PTE_NG)/* only when !PTE_VALID */ +#define PTE_PRESENT_VALID_KERNEL (PTE_VALID | PTE_MAYBE_NG) +#ifdef CONFIG_HAVE_ARCH_USERFAULTFD_WP #define PTE_UFFD_WP (_AT(pteval_t, 1) << 58)/* uffd-wp tracking */ #define PTE_SWP_UFFD_WP (_AT(pteval_t, 1) << 3)/* only for swp ptes */
arch/arm64/include/asm/pgtable.h +7 -2
@@ -357,9 +357,11 @@ static inline pte_t pte_mknoncont(pte_treturn clear_pte_bit (pte,__pgprot (PTE_CONT )); } -static inline pte_t pte_mkvalid (pte_t pte) +static inline pte_t pte_mkvalid_k (pte_t pte) { -return set_pte_bit (pte,__pgprot (PTE_VALID )); + pte =clear_pte_bit (pte,__pgprot (PTE_PRESENT_INVALID )); + pte =set_pte_bit (pte,__pgprot (PTE_PRESENT_VALID_KERNEL )); +return pte; }static inline pte_t pte_mkinvalid (pte_t pte)
@@ -629,6 +631,7 @@ static inline int pmd_protnone(pmd_t pmd#define pmd_mkclean (pmd) pte_pmd(pte_mkclean(pmd_pte(pmd)))#define pmd_mkdirty (pmd) pte_pmd(pte_mkdirty(pmd_pte(pmd)))#define pmd_mkyoung (pmd) pte_pmd(pte_mkyoung(pmd_pte(pmd))) +#define pmd_mkvalid_k (pmd) pte_pmd(pte_mkvalid_k(pmd_pte(pmd)))#define pmd_mkinvalid (pmd) pte_pmd(pte_mkinvalid(pmd_pte(pmd)))#ifdef CONFIG_HAVE_ARCH_USERFAULTFD_WP #define pmd_uffd_wp (pmd) pte_uffd_wp(pmd_pte(pmd))
@@ -670,6 +673,8 @@ static inline pmd_t pmd_mkspecial(pmd_t#define pud_young (pud) pte_young(pud_pte(pud))#define pud_mkyoung (pud) pte_pud(pte_mkyoung(pud_pte(pud))) +#define pud_mkwrite_novma (pud) pte_pud(pte_mkwrite_novma(pud_pte(pud))) +#define pud_mkvalid_k (pud) pte_pud(pte_mkvalid_k(pud_pte(pud)))#define pud_write (pud) pte_write(pud_pte(pud))static inline pud_t pud_mkhuge (pud_t pud)
arch/arm64/mm/mmu.c +4 -0
@@ -602,6 +602,8 @@ static int split_pmd(pmd_t *pmdp, pmd_t tableprot |=PMD_TABLE_PXN ; prot =__pgprot ((pgprot_val (prot) & ~PTE_TYPE_MASK ) |PTE_TYPE_PAGE ); +if (!pmd_valid (pmd)) + prot =pte_pgprot (pte_mkinvalid (pfn_pte (0 , prot))); prot =__pgprot (pgprot_val (prot) & ~PTE_CONT );if (to_cont) prot =__pgprot (pgprot_val (prot) |PTE_CONT );
@@ -647,6 +649,8 @@ static int split_pud(pud_t *pudp, pud_t tableprot |=PUD_TABLE_PXN ; prot =__pgprot ((pgprot_val (prot) & ~PMD_TYPE_MASK ) |PMD_TYPE_SECT ); +if (!pud_valid (pud)) + prot =pmd_pgprot (pmd_mkinvalid (pfn_pmd (0 , prot))); prot =__pgprot (pgprot_val (prot) & ~PTE_CONT );if (to_cont) prot =__pgprot (pgprot_val (prot) |PTE_CONT );
arch/arm64/mm/pageattr.c +28 -22
116 lines not on this page · raw message
arch/arm64/mm/trans_pgd.c +7 -35
66 lines not on this page · raw message
Greg Kroah-Hartman
maintainerPATCH 181/220 media: vidtv: fix NULL pointer dereference in vidtv_channel_pmt_match_sections
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ruslan Valiyev <[email protected]>
commit f8e1fc918a9fe67103bcda01d20d745f264d00a7 upstream.
syzbot reported a general protection fault in vidtv_psi_desc_assign [1].
vidtv_psi_pmt_stream_init() can return NULL on memory allocation failure, but vidtv_channel_pmt_match_sections() does not check for this. When tail is NULL, the subsequent call to vidtv_psi_desc_assign(&tail->descriptor, desc) dereferences a NULL pointer offset, causing a general protection fault.
Add a NULL check after vidtv_psi_pmt_stream_init(). On failure, clean up the already-allocated stream chain and return.
[1]
Oops: general protection fault, probably for non-canonical address 0xdffffc0000000000: 0000 [#1] SMP KASAN PTI KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007] RIP: 0010:vidtv_psi_desc_assign+0x24/0x90 drivers/media/test-drivers/vidtv/vidtv_psi.c:629 Call Trace: <TASK> vidtv_channel_pmt_match_sections drivers/media/test-drivers/vidtv/vidtv_channel.c:349 [inline] vidtv_channel_si_init+0x1445/0x1a50 drivers/media/test-drivers/vidtv/vidtv_channel.c:479 vidtv_mux_init+0x526/0xbe0 drivers/media/test-drivers/vidtv/vidtv_mux.c:519 vidtv_start_streaming drivers/media/test-drivers/vidtv/vidtv_bridge.c:194 [inline] vidtv_start_feed+0x33e/0x4d0 drivers/media/test-drivers/vidtv/vidtv_bridge.c:239
--- drivers/media/test-drivers/vidtv/vidtv_channel.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/media/test-drivers/vidtv/vidtv_channel.c +4 -0
@@ -341,6 +341,10 @@ vidtv_channel_pmt_match_sections(struct tail =vidtv_psi_pmt_stream_init (tail, s->type, e_pid); +if (!tail) { +vidtv_psi_pmt_stream_destroy (head); +return ; + }if (!head) head = tail;
Greg Kroah-Hartman
maintainerPATCH 182/220 ocfs2: fix possible deadlock between unlink and dio_end_io_write
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Joseph Qi <[email protected]>
commit b02da26a992db0c0e2559acbda0fc48d4a2fd337 upstream.
ocfs2_unlink takes orphan dir inode_lock first and then ip_alloc_sem, while in ocfs2_dio_end_io_write, it acquires these locks in reverse order. This creates an ABBA lock ordering violation on lock classes ocfs2_sysfile_lock_key[ORPHAN_DIR_SYSTEM_INODE] and ocfs2_file_ip_alloc_sem_key.
Lock Chain #0 (orphan dir inode_lock -> ip_alloc_sem):ocfs2_unlink
ocfs2_prepare_orphan_dir
ocfs2_lookup_lock_orphan_dir
inode_lock(orphan_dir_inode) <- lock A
__ocfs2_prepare_orphan_dir
ocfs2_prepare_dir_for_insert
ocfs2_extend_dir
ocfs2_expand_inline_dir
down_write(&oi->ip_alloc_sem) <- Lock B
Lock Chain #1 (ip_alloc_sem -> orphan dir inode_lock):ocfs2_dio_end_io_write
down_write(&oi->ip_alloc_sem) <- Lock B ocfs2_del_inode_from_orphan()
inode_lock(orphan_dir_inode) <- Lock A
Deadlock Scenario:
CPU0 (unlink) CPU1 (dio_end_io_write)
------ ------
inode_lock(orphan_dir_inode)
down_write(ip_alloc_sem)
down_write(ip_alloc_sem)
inode_lock(orphan_dir_inode)
Since ip_alloc_sem is to protect allocation changes, which is unrelated with operations in ocfs2_del_inode_from_orphan. So move ocfs2_del_inode_from_orphan out of ip_alloc_sem to fix the deadlock.
--- fs/ocfs2/aops.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
fs/ocfs2/aops.c +1 -2
@@ -2295,8 +2295,6 @@ static int ocfs2_dio_end_io_write(struct goto out; } -down_write (&oi->ip_alloc_sem); -/* Delete orphan before acquire i_rwsem. */ if (dwc->dw_orphaned) {BUG_ON (dwc->dw_writer_pid !=task_pid_nr (current));
@@ -2309,6 +2307,7 @@ static int ocfs2_dio_end_io_write(structmlog_errno (ret); } +down_write (&oi->ip_alloc_sem); di = (struct ocfs2_dinode *)di_bh->b_data;ocfs2_init_dinode_extent_tree (&et,INODE_CACHE (inode), di_bh);
Greg Kroah-Hartman
maintainerPATCH 183/220 ocfs2: fix use-after-free in ocfs2_fault() when VM_FAULT_RETRY
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tejas Bharambe <[email protected]>
commit 7de554cabf160e331e4442e2a9ad874ca9875921 upstream.
filemap_fault() may drop the mmap_lock before returning VM_FAULT_RETRY, as documented in mm/filemap.c:
"If our return value has VM_FAULT_RETRY set, it's because the mmap_lock may be dropped before doing I/O or by lock_folio_maybe_drop_mmap()."
When this happens, a concurrent munmap() can call remove_vma() and free the vm_area_struct via RCU. The saved 'vma' pointer in ocfs2_fault() then becomes a dangling pointer, and the subsequent trace_ocfs2_fault() call dereferences it -- a use-after-free.
Fix this by saving ip_blkno as a plain integer before calling filemap_fault(), and removing vma from the trace event. Since ip_blkno is copied by value before the lock can be dropped, it remains valid regardless of what happens to the vma or inode afterward.
--- fs/ocfs2/mmap.c | 7 +++---- fs/ocfs2/ocfs2_trace.h | 10 ++++------ 2 files changed, 7 insertions(+), 10 deletions(-)
fs/ocfs2/mmap.c +3 -4
@@ -30,7 +30,8 @@static vm_fault_t ocfs2_fault (struct vm_fault *vmf) { -struct vm_area_struct *vma = vmf->vma; +unsigned long long ip_blkno = +OCFS2_I (file_inode (vmf->vma->vm_file))->ip_blkno;sigset_t oldset;vm_fault_t ret;
@@ -38,11 +39,9 @@ static vm_fault_t ocfs2_fault(struct vm_ ret =filemap_fault (vmf);ocfs2_unblock_signals (&oldset); -trace_ocfs2_fault (OCFS2_I (vma->vm_file->f_mapping->host)->ip_blkno, - vma, vmf->page, vmf->pgoff); +trace_ocfs2_fault (ip_blkno, vmf->page, vmf->pgoff);return ret; } -static vm_fault_t __ocfs2_page_mkwrite (struct file *file,struct buffer_head *di_bh,struct folio *folio) {
fs/ocfs2/ocfs2_trace.h +4 -6
@@ -1246,22 +1246,20 @@ TRACE_EVENT(ocfs2_write_end_inline,TRACE_EVENT (ocfs2_fault, TP_PROTO(unsigned long long ino, - void *area, void *page, unsigned long pgoff), -TP_ARGS (ino, area, page, pgoff), + void *page, unsigned long pgoff), +TP_ARGS (ino, page, pgoff),TP_STRUCT__entry ( __field(unsigned long long, ino) - __field(void *, area) __field(void *, page) __field(unsigned long, pgoff) ),TP_fast_assign ( __entry->ino = ino; - __entry->area = area; __entry->page = page; __entry->pgoff = pgoff; ), -TP_printk ("%llu %p %p %lu" , - __entry->ino, __entry->area, __entry->page, __entry->pgoff) +TP_printk ("%llu %p %lu" , + __entry->ino, __entry->page, __entry->pgoff) );/* End of trace events for fs/ocfs2/mmap.c. */
Greg Kroah-Hartman
maintainerPATCH 184/220 ocfs2: handle invalid dinode in ocfs2_group_extend
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: ZhengYuan Huang <[email protected]>
commit 4a1c0ddc6e7bcf2e9db0eeaab9340dcfe97f448f upstream.
[BUG]
kernel BUG at fs/ocfs2/resize.c:308!
Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI RIP: 0010:ocfs2_group_extend+0x10aa/0x1ae0 fs/ocfs2/resize.c:308 Code: 8b8520ff ffff83f8 860f8580 030000e8 5cc3c1fe Call Trace: ... ocfs2_ioctl+0x175/0x6e0 fs/ocfs2/ioctl.c:869 vfs_ioctl fs/ioctl.c:51 [inline] __do_sys_ioctl fs/ioctl.c:597 [inline] __se_sys_ioctl fs/ioctl.c:583 [inline] __x64_sys_ioctl+0x197/0x1e0 fs/ioctl.c:583 x64_sys_call+0x1144/0x26a0 arch/x86/include/generated/asm/syscalls_64.h:17 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] do_syscall_64+0x93/0xf80 arch/x86/entry/syscall_64.c:94 entry_SYSCALL_64_after_hwframe+0x76/0x7e ...
[CAUSE]ocfs2_group_extend() assumes that the global bitmap inode block returned from ocfs2_inode_lock() has already been validated and BUG_ONs when the signature is not a dinode. That assumption is too strong for crafted filesystems because the JBD2-managed buffer path can bypass structural validation and return an invalid dinode to the resize ioctl.
[FIX]
Validate the dinode explicitly in ocfs2_group_extend(). If the global bitmap buffer does not contain a valid dinode, report filesystem corruption with ocfs2_error() and fail the resize operation instead of crashing the kernel.
--- fs/ocfs2/resize.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-)
fs/ocfs2/resize.c +7 -3
@@ -303,9 +303,13 @@ int ocfs2_group_extend(struct inode * in fe = (struct ocfs2_dinode *)main_bm_bh->b_data; -/* main_bm_bh is validated by inode read inside ocfs2_inode_lock(), -* so any corruption is a code bug. */ -BUG_ON (!OCFS2_IS_VALID_DINODE (fe)); +/* JBD-managed buffers can bypass validation, so treat this as corruption. */ +if (!OCFS2_IS_VALID_DINODE (fe)) { + ret =ocfs2_error (main_bm_inode->i_sb, +"Invalid dinode #%llu\n" , + (unsigned long long )OCFS2_I (main_bm_inode)->ip_blkno); + goto out_unlock; + }if (le16_to_cpu (fe->id2.i_chain.cl_cpg) != ocfs2_group_bitmap_size(osb->sb, 0,
Greg Kroah-Hartman
maintainerPATCH 185/220 PCI: endpoint: pci-epf-vntb: Stop cmd_handler work in epf_ntb_epc_cleanup
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Koichiro Den <[email protected]>
commit d799984233a50abd2667a7d17a9a710a3f10ebe2 upstream.
Disable the delayed work before clearing BAR mappings and doorbells to avoid running the handler after resources have been torn down.
Unable to handle kernel paging request at virtual address ffff800083f46004 [...] Internal error: Oops: 0000000096000007 [#1] SMP [...] Call trace: epf_ntb_cmd_handler+0x54/0x200 [pci_epf_vntb] (P) process_one_work+0x154/0x3b0 worker_thread+0x2c8/0x400 kthread+0x148/0x210 ret_from_fork+0x10/0x20
--- drivers/pci/endpoint/functions/pci-epf-vntb.c | 1 + 1 file changed, 1 insertion(+)
drivers/pci/endpoint/functions/pci-epf-vntb.c +1 -0
@@ -955,6 +955,7 @@ err_config_interrupt:*/ static void epf_ntb_epc_cleanup (struct epf_ntb *ntb) { +disable_delayed_work_sync (&ntb->cmd_handler);epf_ntb_mw_bar_clear (ntb, ntb->num_mws);epf_ntb_db_bar_clear (ntb);epf_ntb_config_sspad_bar_clear (ntb);
Greg Kroah-Hartman
maintainerPATCH 186/220 PCI: endpoint: pci-epf-vntb: Remove duplicate resource teardown
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Koichiro Den <[email protected]>
commit 0da63230d3ec1ec5fcc443a2314233e95bfece54 upstream.
epf_ntb_epc_destroy() duplicates the teardown that the caller is supposed to perform later. This leads to an oops when .allow_link fails or when .drop_link is performed. The following is an example oops of the former case:
Unable to handle kernel paging request at virtual address dead000000000108 [...] [dead000000000108] address between user and kernel address ranges Internal error: Oops: 0000000096000044 [#1] SMP [...] Call trace: pci_epc_remove_epf+0x78/0xe0 (P) pci_primary_epc_epf_link+0x88/0xa8 configfs_symlink+0x1f4/0x5a0 vfs_symlink+0x134/0x1d8 do_symlinkat+0x88/0x138 __arm64_sys_symlinkat+0x74/0xe0 [...]
Remove the helper, and drop pci_epc_put(). EPC device refcounting is tied to the configfs EPC group lifetime, and pci_epc_put() in the .drop_link path is sufficient.
--- drivers/pci/endpoint/functions/pci-epf-vntb.c | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-)
drivers/pci/endpoint/functions/pci-epf-vntb.c +1 -18
@@ -764,19 +764,6 @@ static void epf_ntb_mw_bar_clear(struct }/** -* epf_ntb_epc_destroy() - Cleanup NTB EPC interface -* @ntb: NTB device that facilitates communication between HOST and VHOST -* -* Wrapper for epf_ntb_epc_destroy_interface() to cleanup all the NTB interfaces -*/ -static void epf_ntb_epc_destroy (struct epf_ntb *ntb) -{ -pci_epc_remove_epf (ntb->epf->epc, ntb->epf,0 ); -pci_epc_put (ntb->epf->epc); -} - - -/** * epf_ntb_is_bar_used() - Check if a bar is used in the ntb configuration * @ntb: NTB device that facilitates communication between HOST and VHOST * @barno: Checked bar number
@@ -1526,7 +1513,7 @@ static int epf_ntb_bind(struct pci_epf * ret =epf_ntb_init_epc_bar (ntb);if (ret) {dev_err (dev,"Failed to create NTB EPC\n" ); - goto err_bar_init; +return ret; } ret =epf_ntb_config_spad_bar_alloc (ntb);
@@ -1566,9 +1553,6 @@ err_epc_cleanup: err_bar_alloc:epf_ntb_config_spad_bar_free (ntb); -err_bar_init: -epf_ntb_epc_destroy (ntb); -return ret; }
@@ -1584,7 +1568,6 @@ static void epf_ntb_unbind(struct pci_epepf_ntb_epc_cleanup (ntb);epf_ntb_config_spad_bar_free (ntb); -epf_ntb_epc_destroy (ntb);pci_unregister_driver (&vntb_pci_driver); }
Greg Kroah-Hartman
maintainerPATCH 187/220 KVM: selftests: Remove duplicate LAUNCH_UPDATE_VMSA call in SEV-ES migrate test
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sean Christopherson <[email protected]>
commit 25a642b6abc98bbbabbf2baef9fc498bbea6aee6 upstream.
Drop the explicit KVM_SEV_LAUNCH_UPDATE_VMSA call when creating an SEV-ES VM in the SEV migration test, as sev_vm_create() automatically updates the VMSA pages for SEV-ES guests. The only reason the duplicate call doesn't cause visible problems is because the test doesn't actually try to run the vCPUs. That will change when KVM adds a check to prevent userspace from re-launching a VMSA (which corrupts the VMSA page due to KVM writing encrypted private memory).
--- tools/testing/selftests/kvm/x86/sev_migrate_tests.c | 2 -- 1 file changed, 2 deletions(-)
tools/testing/selftests/kvm/x86/sev_migrate_tests.c +0 -2
@@ -36,8 +36,6 @@ static struct kvm_vm *sev_vm_create(boolsev_vm_launch (vm, es ?SEV_POLICY_ES :0 ); -if (es) -vm_sev_ioctl (vm,KVM_SEV_LAUNCH_UPDATE_VMSA ,NULL );return vm; }
Greg Kroah-Hartman
maintainerPATCH 188/220 KVM: SEV: Reject attempts to sync VMSA of an already-launched/encrypted vCPU
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sean Christopherson <[email protected]>
commit 9b9f7962e3e879d12da2bf47e02a24ec51690e3d upstream.
Reject synchronizing vCPU state to its associated VMSA if the vCPU has already been launched, i.e. if the VMSA has already been encrypted. On a host with SNP enabled, accessing guest-private memory generates an RMP #PF and panics the host.
BUG: unable to handle page fault for address: ff1276cbfdf36000 #PF: supervisor write access in kernel mode #PF: error_code(0x80000003) - RMP violation PGD 5a31801067 P4D 5a31802067 PUD 40ccfb5063 PMD 40e5954063 PTE 80000040fdf36163 SEV-SNP: PFN 0x40fdf36, RMP entry: [0x6010fffffffff001 - 0x000000000000001f] Oops: Oops: 0003 [#1] SMP NOPTI CPU: 33 UID: 0 PID: 996180 Comm: qemu-system-x86 Tainted: G OE Tainted: [O]=OOT_MODULE, [E]=UNSIGNED_MODULE Hardware name: Dell Inc. PowerEdge R7625/0H1TJT, BIOS 1.5.8 07/21/2023 RIP: 0010:sev_es_sync_vmsa+0x54/0x4c0 [kvm_amd] Call Trace: <TASK> snp_launch_update_vmsa+0x19d/0x290 [kvm_amd] snp_launch_finish+0xb6/0x380 [kvm_amd] sev_mem_enc_ioctl+0x14e/0x720 [kvm_amd] kvm_arch_vm_ioctl+0x837/0xcf0 [kvm] kvm_vm_ioctl+0x3fd/0xcc0 [kvm] __x64_sys_ioctl+0xa3/0x100 x64_sys_call+0xfe0/0x2350 do_syscall_64+0x81/0x10f0 entry_SYSCALL_64_after_hwframe+0x76/0x7e RIP: 0033:0x7ffff673287d </TASK>
Note, the KVM flaw has been present since commit ad73109ae7ec ("KVM: SVM:
Provide support to launch and run an SEV-ES guest"), but has only been actively dangerous for the host since SNP support was added. With SEV-ES, KVM would "just" clobber guest state, which is totally fine from a host kernel perspective since userspace can clobber guest state any time before sev_launch_update_vmsa().
--- arch/x86/kvm/svm/sev.c | 3 +++ 1 file changed, 3 insertions(+)
arch/x86/kvm/svm/sev.c +3 -0
@@ -875,6 +875,9 @@ static int sev_es_sync_vmsa(struct vcpu_u8 *d;int i; +if (vcpu->arch.guest_state_protected) +return -EINVAL ; +/* Check some debug related fields before encrypting the VMSA */ if (svm->vcpu.guest_debug || (svm->vmcb->save.dr7 & ~DR7_FIXED_1 ))return -EINVAL ;
Greg Kroah-Hartman
maintainerPATCH 189/220 KVM: SEV: Protect *all* of sev_mem_enc_register_region() with kvm->lock
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sean Christopherson <[email protected]>
commit b6408b6cec5df76a165575777800ef2aba12b109 upstream.
Take and hold kvm->lock for before checking sev_guest() in sev_mem_enc_register_region(), as sev_guest() isn't stable unless kvm->lock is held (or KVM can guarantee KVM_SEV_INIT{2} has completed and can't rollack state). If KVM_SEV_INIT{2} fails, KVM can end up trying to add to a not-yet-initialized sev->regions_list, e.g. triggering a #GP
Oops: general protection fault, probably for non-canonical address 0xdffffc0000000000: 0000 [#1] SMP KASAN NOPTI KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007] CPU: 110 UID: 0 PID: 72717 Comm: syz.15.11462 Tainted: G U W O 6.16.0-smp-DEV #1 NONE Tainted: [U]=USER, [W]=WARN, [O]=OOT_MODULE Hardware name: Google, Inc. Arcadia_IT_80/Arcadia_IT_80, BIOS 12.52.0-0 10/28/2024 RIP: 0010:sev_mem_enc_register_region+0x3f0/0x4f0 ../include/linux/list.h:83 Code: <41> 80 3c 04 00 74 08 4c 89 ff e8 f1 c7 a2 00 49 39 ed 0f 84 c6 00 RSP: 0018:ffff88838647fbb8 EFLAGS: 00010256 RAX: dffffc0000000000 RBX: 1ffff92015cf1e0b RCX: dffffc0000000000 RDX: 0000000000000000 RSI: 0000000000001000 RDI: ffff888367870000 RBP: ffffc900ae78f050 R08: ffffea000d9e0007 R09: 1ffffd4001b3c000 R10: dffffc0000000000 R11: fffff94001b3c001 R12: 0000000000000000 R13: ffff8982ab0bde00 R14: ffffc900ae78f058 R15: 0000000000000000 FS: 00007f34e9dc66c0(0000) GS:ffff89ee64d33000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007fe180adef98 CR3: 000000047210e000 CR4: 0000000000350ef0 Call Trace: <TASK> kvm_arch_vm_ioctl+0xa72/0x1240 ../arch/x86/kvm/x86.c:7371 kvm_vm_ioctl+0x649/0x990 ../virt/kvm/kvm_main.c:5363 __se_sys_ioctl+0x101/0x170 ../fs/ioctl.c:51 do_syscall_x64 ../arch/x86/entry/syscall_64.c:63 [inline] do_syscall_64+0x6f/0x1f0 ../arch/x86/entry/syscall_64.c:94 entry_SYSCALL_64_after_hwframe+0x76/0x7e RIP: 0033:0x7f34e9f7e9a9 Code: <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 a8 ff ff ff f7 d8 64 89 01 48 RSP: 002b:00007f34e9dc6038 EFLAGS: 00000246 ORIG_RAX: 0000000000000010 RAX: ffffffffffffffda RBX: 00007f34ea1a6080 RCX: 00007f34e9f7e9a9 RDX: 0000200000000280 RSI: 000000008010aebb RDI: 0000000000000007 RBP: 00007f34ea000d69 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000 R13: 0000000000000000 R14: 00007f34ea1a6080 R15: 00007ffce77197a8 </TASK>
with a syzlang reproducer that looks like:
syz_kvm_add_vcpu$x86(0x0, &(0x7f0000000040)={0x0, &(0x7f0000000180)=ANY=[], 0x70}) (async) syz_kvm_add_vcpu$x86(0x0, &(0x7f0000000080)={0x0, &(0x7f0000000180)=ANY=[@ANYBLOB="..."], 0x4f}) (async)
r0 = openat$kvm(0xffffffffffffff9c, &(0x7f0000000200), 0x0, 0x0)
r1 = ioctl$KVM_CREATE_VM(r0, 0xae01, 0x0)
r2 = openat$kvm(0xffffffffffffff9c, &(0x7f0000000240), 0x0, 0x0)
r3 = ioctl$KVM_CREATE_VM(r2, 0xae01, 0x0)
ioctl$KVM_SET_CLOCK(r3, 0xc008aeba, &(0x7f0000000040)={0x1, 0x8, 0x0, 0x5625e9b0}) (async) ioctl$KVM_SET_PIT2(r3, 0x8010aebb, &(0x7f0000000280)={[...], 0x5}) (async)
ioctl$KVM_SET_PIT2(r1, 0x4070aea0, 0x0) (async)
r4 = ioctl$KVM_CREATE_VM(0xffffffffffffffff, 0xae01, 0x0)
openat$kvm(0xffffffffffffff9c, 0x0, 0x0, 0x0) (async)
ioctl$KVM_SET_USER_MEMORY_REGION(r4, 0x4020ae46, &(0x7f0000000400)={0x0, 0x0, 0x0, 0x2000, &(0x7f0000001000/0x2000)=nil}) (async) r5 = ioctl$KVM_CREATE_VCPU(r4, 0xae41, 0x2)
close(r0) (async)
openat$kvm(0xffffffffffffff9c, &(0x7f0000000000), 0x8000, 0x0) (async)
ioctl$KVM_SET_GUEST_DEBUG(r5, 0x4048ae9b, &(0x7f0000000300)={0x4376ea830d46549b, 0x0, [0x46, 0x0, 0x0, 0x0, 0x0, 0x1000]}) (async) ioctl$KVM_RUN(r5, 0xae80, 0x0)
Opportunistically use guard() to avoid having to define a new error label and goto usage.
--- arch/x86/kvm/svm/sev.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
arch/x86/kvm/svm/sev.c +2 -4
@@ -2695,6 +2695,8 @@ int sev_mem_enc_register_region(struct kstruct enc_region *region;int ret =0 ; +guard (mutex)(&kvm->lock); +if (!sev_guest (kvm))return -ENOTTY ;
@@ -2709,12 +2711,10 @@ int sev_mem_enc_register_region(struct kif (!region)return -ENOMEM ; -mutex_lock (&kvm->lock); region->pages =sev_pin_memory (kvm, range->addr, range->size, ®ion->npages,FOLL_WRITE |FOLL_LONGTERM );if (IS_ERR (region->pages)) { ret =PTR_ERR (region->pages); -mutex_unlock (&kvm->lock); goto e_free; }
@@ -2732,8 +2732,6 @@ int sev_mem_enc_register_region(struct k region->size = range->size;list_add_tail (®ion->list, &sev->regions_list); -mutex_unlock (&kvm->lock); -return ret; e_free:
Greg Kroah-Hartman
maintainerPATCH 190/220 KVM: SEV: Disallow LAUNCH_FINISH if vCPUs are actively being created
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sean Christopherson <[email protected]>
commit 624bf3440d7214b62c22d698a0a294323f331d5d upstream.
Reject LAUNCH_FINISH for SEV-ES and SNP VMs if KVM is actively creating one or more vCPUs, as KVM needs to process and encrypt each vCPU's VMSA. Letting userspace create vCPUs while LAUNCH_FINISH is in-progress is "fine", at least in the current code base, as kvm_for_each_vcpu() operates on online_vcpus, LAUNCH_FINISH (all SEV+ sub-ioctls) holds kvm->mutex, and fully onlining a vCPU in kvm_vm_ioctl_create_vcpu() is done under kvm->mutex. I.e. there's no difference between an in-progress vCPU and a vCPU that is created entirely after LAUNCH_FINISH.
However, given that concurrent LAUNCH_FINISH and vCPU creation can't possibly work (for any reasonable definition of "work"), since userspace can't guarantee whether a particular vCPU will be encrypted or not, disallow the combination as a hardening measure, to reduce the probability of introducing bugs in the future, and to avoid having to reason about the safety of future changes related to LAUNCH_FINISH.
--- arch/x86/kvm/svm/sev.c | 10 ++++++++-- include/linux/kvm_host.h | 7 +++++++ 2 files changed, 15 insertions(+), 2 deletions(-)
arch/x86/kvm/svm/sev.c +8 -2
@@ -1023,6 +1023,9 @@ static int sev_launch_update_vmsa(structif (!sev_es_guest (kvm))return -ENOTTY ; +if (kvm_is_vcpu_creation_in_progress (kvm)) +return -EBUSY ; +kvm_for_each_vcpu (i, vcpu, kvm) { ret =mutex_lock_killable (&vcpu->mutex);if (ret)
@@ -2043,8 +2046,8 @@ static int sev_check_source_vcpus(structstruct kvm_vcpu *src_vcpu;unsigned long i; -if (src->created_vcpus !=atomic_read (&src->online_vcpus) || - dst->created_vcpus !=atomic_read (&dst->online_vcpus)) +if (kvm_is_vcpu_creation_in_progress (src) || +kvm_is_vcpu_creation_in_progress (dst))return -EBUSY ;if (!sev_es_guest (src))
@@ -2454,6 +2457,9 @@ static int snp_launch_update_vmsa(structunsigned long i;int ret; +if (kvm_is_vcpu_creation_in_progress (kvm)) +return -EBUSY ; + data.gctx_paddr =__psp_pa (sev->snp_context); data.page_type =SNP_PAGE_TYPE_VMSA ;
include/linux/kvm_host.h +7 -0
@@ -1030,6 +1030,13 @@ static inline struct kvm_vcpu *kvm_get_vreturn NULL ; } +static inline bool kvm_is_vcpu_creation_in_progress (struct kvm *kvm) +{ +lockdep_assert_held (&kvm->lock); + +return kvm->created_vcpus !=atomic_read (&kvm->online_vcpus); +} +void kvm_destroy_vcpus (struct kvm *kvm);int kvm_trylock_all_vcpus (struct kvm *kvm);
Greg Kroah-Hartman
maintainerPATCH 191/220 KVM: SEV: Lock all vCPUs when synchronzing VMSAs for SNP launch finish
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sean Christopherson <[email protected]>
commit cb923ee6a80f4e604e6242a4702b59251e61a380 upstream.
Lock all vCPUs when synchronizing and encrypting VMSAs for SNP guests, as allowing userspace to manipulate and/or run a vCPU while its state is being synchronized would at best corrupt vCPU state, and at worst crash the host kernel.
Opportunistically assert that vcpu->mutex is held when synchronizing its VMSA (the SEV-ES path already locks vCPUs).
--- arch/x86/kvm/svm/sev.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-)
arch/x86/kvm/svm/sev.c +12 -4
@@ -875,6 +875,8 @@ static int sev_es_sync_vmsa(struct vcpu_u8 *d;int i; +lockdep_assert_held (&vcpu->mutex); +if (vcpu->arch.guest_state_protected)return -EINVAL ;
@@ -2460,6 +2462,10 @@ static int snp_launch_update_vmsa(structif (kvm_is_vcpu_creation_in_progress (kvm))return -EBUSY ; + ret =kvm_lock_all_vcpus (kvm); +if (ret) +return ret; + data.gctx_paddr =__psp_pa (sev->snp_context); data.page_type =SNP_PAGE_TYPE_VMSA ;
@@ -2469,12 +2475,12 @@ static int snp_launch_update_vmsa(struct ret =sev_es_sync_vmsa (svm);if (ret) -return ret; + goto out;/* Transition the VMSA page to a firmware state. */ ret =rmp_make_private (pfn,INITIAL_VMSA_GPA ,PG_LEVEL_4K , sev->asid, true);if (ret) -return ret; + goto out;/* Issue the SNP command to encrypt the VMSA */ data.address =__sme_pa (svm->sev_es.vmsa);
@@ -2483,7 +2489,7 @@ static int snp_launch_update_vmsa(structif (ret) {snp_page_reclaim (kvm, pfn); -return ret; + goto out; } svm->vcpu.arch.guest_state_protected = true;
@@ -2497,7 +2503,9 @@ static int snp_launch_update_vmsa(structsvm_enable_lbrv (vcpu); } -return 0 ; +out: +kvm_unlock_all_vcpus (kvm); +return ret; }static int snp_launch_finish (struct kvm *kvm,struct kvm_sev_cmd *argp)
Greg Kroah-Hartman
maintainerPATCH 192/220 KVM: SEV: Drop WARN on large size for KVM_MEMORY_ENCRYPT_REG_REGION
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sean Christopherson <[email protected]>
commit 8acffeef5ef720c35e513e322ab08e32683f32f2 upstream.
Drop the WARN in sev_pin_memory() on npages overflowing an int, as the WARN is comically trivially to trigger from userspace, e.g. by doing:
struct kvm_enc_region range = {
.addr = 0,
.size = -1ul,
};
__vm_ioctl(vm, KVM_MEMORY_ENCRYPT_REG_REGION, &range);Note, the checks in sev_mem_enc_register_region() that presumably exist to verify the incoming address+size are completely worthless, as both "addr" and "size" are u64s and SEV is 64-bit only, i.e. they _can't_ be greater than ULONG_MAX. That wart will be cleaned up in the near future.
if (range->addr > ULONG_MAX || range->size > ULONG_MAX) return -EINVAL;
Opportunistically add a comment to explain why the code calculates the number of pages the "hard" way, e.g. instead of just shifting @ulen.
--- arch/x86/kvm/svm/sev.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-)
arch/x86/kvm/svm/sev.c +7 -4
@@ -683,10 +683,16 @@ static struct page **sev_pin_memory(struif (ulen ==0 || uaddr + ulen < uaddr)return ERR_PTR (-EINVAL ); -/* Calculate number of pages. */ +/* +* Calculate the number of pages that need to be pinned to cover the +* entire range. Note! This isn't simply ulen >> PAGE_SHIFT, as KVM +* doesn't require the incoming address+size to be page aligned! +*/ first = (uaddr &PAGE_MASK ) >>PAGE_SHIFT ; last = ((uaddr + ulen -1 ) &PAGE_MASK ) >>PAGE_SHIFT ; npages = (last - first +1 ); +if (npages >INT_MAX ) +return ERR_PTR (-EINVAL ); locked = sev->pages_locked + npages; lock_limit =rlimit (RLIMIT_MEMLOCK ) >>PAGE_SHIFT ;
@@ -695,9 +701,6 @@ static struct page **sev_pin_memory(strureturn ERR_PTR (-ENOMEM ); } -if (WARN_ON_ONCE (npages >INT_MAX )) -return ERR_PTR (-EINVAL ); -/* Avoid using vmalloc for smaller buffers. */ size = npages *sizeof (struct page *);if (size >PAGE_SIZE )
Greg Kroah-Hartman
maintainerPATCH 193/220 mm: call ->free_folio() directly in folio_unmap_invalidate()
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matthew Wilcox (Oracle) <[email protected]>
commit 615d9bb2ccad42f9e21d837431e401db2e471195 upstream.
We can only call filemap_free_folio() if we have a reference to (or hold a lock on) the mapping. Otherwise, we've already removed the folio from the mapping so it no longer pins the mapping and the mapping can be removed, causing a use-after-free when accessing mapping->a_ops.
Follow the same pattern as __remove_mapping() and load the free_folio function pointer before dropping the lock on the mapping. That lets us make filemap_free_folio() static as this was the only caller outside filemap.c.
--- mm/filemap.c | 3 ++- mm/internal.h | 1 - mm/truncate.c | 6 +++++- 3 files changed, 7 insertions(+), 3 deletions(-)
mm/filemap.c +2 -1
@@ -228,7 +228,8 @@ void __filemap_remove_folio(struct foliopage_cache_delete (mapping, folio, shadow); } -void filemap_free_folio (struct address_space *mapping,struct folio *folio) +static void filemap_free_folio (const struct address_space *mapping, +struct folio *folio) {void (*free_folio)(struct folio *);
mm/internal.h +0 -1
@@ -471,7 +471,6 @@ unsigned find_lock_entries(struct addres pgoff_t end, struct folio_batch *fbatch, pgoff_t *indices);unsigned find_get_entries (struct address_space *mapping,pgoff_t *start,pgoff_t end,struct folio_batch *fbatch,pgoff_t *indices); -void filemap_free_folio (struct address_space *mapping,struct folio *folio);int truncate_inode_folio (struct address_space *mapping,struct folio *folio);bool truncate_inode_partial_folio (struct folio *folio,loff_t start,loff_t end);
mm/truncate.c +5 -1
@@ -622,6 +622,7 @@ static int folio_launder(struct address_int folio_unmap_invalidate (struct address_space *mapping,struct folio *folio,gfp_t gfp) { +void (*free_folio)(struct folio *);int ret;VM_BUG_ON_FOLIO (!folio_test_locked (folio), folio);
@@ -648,9 +649,12 @@ int folio_unmap_invalidate(struct addresxa_unlock_irq (&mapping->i_pages);if (mapping_shrinkable (mapping))inode_lru_list_add (mapping->host); + free_folio = mapping->a_ops->free_folio;spin_unlock (&mapping->host->i_lock); -filemap_free_folio (mapping, folio); +if (free_folio) +free_folio (folio); +folio_put_refs (folio,folio_nr_pages (folio));return 1 ; failed:xa_unlock_irq (&mapping->i_pages);
Greg Kroah-Hartman
maintainerPATCH 194/220 selftests/bpf: Test refinement of single-value tnum
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paul Chaignon <[email protected]>
commit e6ad477d1bf8829973cddd9accbafa9d1a6cd15a upstream.
This patch introduces selftests to cover the new bounds refinement logic introduced in the previous patch. Without the previous patch, the first two tests fail because of the invariant violation they trigger. The last test fails because the R10 access is not detected as dead code. In addition, all three tests fail because of R0 having a non-constant value in the verifier logs.
In addition, the last two cases are covering the negative cases: when we shouldn't refine the bounds because the u64 and tnum overlap in at least two values.
[shung-hsi.yu: test for backported upstream commit efc11a667878 ("bpf: Improve bounds when tnum has a single possible value")]
--- tools/testing/selftests/bpf/progs/verifier_bounds.c | 137 ++++++++++++++++++++ 1 file changed, 137 insertions(+)
tools/testing/selftests/bpf/progs/verifier_bounds.c +137 -0
@@ -1863,4 +1863,141 @@ l1_%=: r0 = 1; \ : __clobber_all); } +/* This test covers the bounds deduction when the u64 range and the tnum +* overlap only at umax. After instruction 3, the ranges look as follows: +* +* 0 umin=0xe01 umax=0xf00 U64_MAX +* | [xxxxxxxxxxxxxx] | +* |----------------------------|------------------------------| +* | x x | tnum values +* +* The verifier can therefore deduce that the R0=0xf0=240. +*/ +SEC("socket") +__description("bounds refinement with single-value tnum on umax") +__msg("3: (15) if r0 == 0xe0 {{.*}} R0=240") +__success __log_level(2) +__flag (BPF_F_TEST_REG_INVARIANTS) +__naked void bounds_refinement_tnum_umax(void *ctx) +{ + asmvolatile (" \ +call %[bpf_get_prandom_u32]; \ +r0 |= 0xe0; \ +r0 &= 0xf0; \ +if r0 == 0xe0 goto +2; \ +if r0 == 0xf0 goto +1; \ +r10 = 0; \ +exit; \ +" : + : __imm(bpf_get_prandom_u32) + : __clobber_all); +} + +/* This test covers the bounds deduction when the u64 range and the tnum +* overlap only at umin. After instruction 3, the ranges look as follows: +* +* 0 umin=0xe00 umax=0xeff U64_MAX +* | [xxxxxxxxxxxxxx] | +* |----------------------------|------------------------------| +* | x x | tnum values +* +* The verifier can therefore deduce that the R0=0xe0=224. +*/ +SEC("socket") +__description("bounds refinement with single-value tnum on umin") +__msg("3: (15) if r0 == 0xf0 {{.*}} R0=224") +__success __log_level(2) +__flag (BPF_F_TEST_REG_INVARIANTS) +__naked void bounds_refinement_tnum_umin(void *ctx) +{ + asmvolatile (" \ +call %[bpf_get_prandom_u32]; \ +r0 |= 0xe0; \ +r0 &= 0xf0; \ +if r0 == 0xf0 goto +2; \ +if r0 == 0xe0 goto +1; \ +r10 = 0; \ +exit; \ +" : + : __imm(bpf_get_prandom_u32) + : __clobber_all); +} + +/* This test covers the bounds deduction when the only possible tnum value is +* in the middle of the u64 range. After instruction 3, the ranges look as +* follows: +* +* 0 umin=0x7cf umax=0x7df U64_MAX +* | [xxxxxxxxxxxx] | +* |----------------------------|------------------------------| +* | x x x x x | tnum values +* | +--- 0x7e0 +* +--- 0x7d0 +* +* Since the lower four bits are zero, the tnum and the u64 range only overlap +* in R0=0x7d0=2000. Instruction 5 is therefore dead code. +*/ +SEC("socket") +__description("bounds refinement with single-value tnum in middle of range") +__msg("3: (a5) if r0 < 0x7cf {{.*}} R0=2000") +__success __log_level(2) +__naked void bounds_refinement_tnum_middle(void *ctx) +{ + asmvolatile (" \ +call %[bpf_get_prandom_u32]; \ +if r0 & 0x0f goto +4; \ +if r0 > 0x7df goto +3; \ +if r0 < 0x7cf goto +2; \ +if r0 == 0x7d0 goto +1; \ +r10 = 0; \ +exit; \ +" : + : __imm(bpf_get_prandom_u32) + : __clobber_all); +} + +/* This test cover the negative case for the tnum/u64 overlap. Since +* they contain the same two values (i.e., {0, 1}), we can't deduce +* anything more. +*/ +SEC("socket") +__description("bounds refinement: several overlaps between tnum and u64") +__msg("2: (25) if r0 > 0x1 {{.*}} R0=scalar(smin=smin32=0,smax=umax=smax32=umax32=1,var_off=(0x0; 0x1))") +__failure __log_level(2) +__naked void bounds_refinement_several_overlaps(void *ctx) +{ + asm volatile(" \ + call %[bpf_get_prandom_u32]; \ + if r0 < 0 goto +3; \ + if r0 > 1 goto +2; \ + if r0 == 1 goto +1; \ + r10 = 0; \ + exit; \ +" : + : __imm(bpf_get_prandom_u32) + : __clobber_all); +} + +/* This test cover the negative case for the tnum/u64 overlap. Since +* they overlap in the two values contained by the u64 range (i.e., +* {0xf, 0x10}), we can't deduce anything more. +*/ +SEC("socket") +__description("bounds refinement: multiple overlaps between tnum and u64") +__msg("2: (25) if r0 > 0x10 {{.*}} R0=scalar(smin=umin=smin32=umin32=15,smax=umax=smax32=umax32=16,var_off=(0x0; 0x1f))") +__failure __log_level(2) +__naked void bounds_refinement_multiple_overlaps(void *ctx) +{ + asm volatile(" \ + call %[bpf_get_prandom_u32]; \ + if r0 < 0xf goto +3; \ + if r0 > 0x10 goto +2; \ + if r0 == 0x10 goto +1; \ + r10 = 0; \ + exit; \ +" : + : __imm(bpf_get_prandom_u32) + : __clobber_all); +} + char _license[] SEC("license") = "GPL";
Greg Kroah-Hartman
maintainerPATCH 195/220 KVM: Remove subtle "struct kvm_stats_desc" pseudo-overlay
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sean Christopherson <[email protected]>
[ Upstream commit da142f3d373a6ddaca0119615a8db2175ddc4121 ]
Remove KVM's internal pseudo-overlay of kvm_stats_desc, which subtly aliases the flexible name[] in the uAPI definition with a fixed-size array of the same name. The unusual embedded structure results in compiler warnings due to -Wflex-array-member-not-at-end, and also necessitates an extra level of dereferencing in KVM. To avoid the "overlay", define the uAPI structure to have a fixed-size name when building for the kernel.
Opportunistically clean up the indentation for the stats macros, and replace spaces with tabs.
No functional change intended.
Stable-dep-of: 2619da73bb2f ("KVM: x86: Use __DECLARE_FLEX_ARRAY() for UAPI structures with VLAs")
--- arch/arm64/kvm/guest.c | 4 +- arch/loongarch/kvm/vcpu.c | 2 - arch/loongarch/kvm/vm.c | 2 - arch/mips/kvm/mips.c | 4 +- arch/powerpc/kvm/book3s.c | 4 +- arch/powerpc/kvm/booke.c | 4 +- arch/riscv/kvm/vcpu.c | 2 - arch/riscv/kvm/vm.c | 2 - arch/s390/kvm/kvm-s390.c | 4 +- arch/x86/kvm/x86.c | 4 +- include/linux/kvm_host.h | 83 +++++++++++++++++++--------------------------- include/uapi/linux/kvm.h | 8 ++++ virt/kvm/binary_stats.c | 2 - virt/kvm/kvm_main.c | 20 +++++------ 14 files changed, 70 insertions(+), 75 deletions(-)
arch/arm64/kvm/guest.c +2 -2
@@ -29,7 +29,7 @@#include "trace.h" -const struct _kvm_stats_desc kvm_vm_stats_desc[] = { +const struct kvm_stats_desc kvm_vm_stats_desc[] = {KVM_GENERIC_VM_STATS () };
@@ -42,7 +42,7 @@ const struct kvm_stats_header kvm_vm_sta sizeof(kvm_vm_stats_desc), }; -const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = { +const struct kvm_stats_desc kvm_vcpu_stats_desc[] = {KVM_GENERIC_VCPU_STATS (),STATS_DESC_COUNTER (VCPU , hvc_exit_stat),STATS_DESC_COUNTER (VCPU , wfe_exit_stat),
arch/loongarch/kvm/vcpu.c +1 -1
@@ -14,7 +14,7 @@#define CREATE_TRACE_POINTS #include "trace.h" -const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = { +const struct kvm_stats_desc kvm_vcpu_stats_desc[] = {KVM_GENERIC_VCPU_STATS (),STATS_DESC_COUNTER (VCPU , int_exits),STATS_DESC_COUNTER (VCPU , idle_exits),
arch/loongarch/kvm/vm.c +1 -1
@@ -10,7 +10,7 @@#include <asm/kvm_eiointc.h> #include <asm/kvm_pch_pic.h> -const struct _kvm_stats_desc kvm_vm_stats_desc[] = { +const struct kvm_stats_desc kvm_vm_stats_desc[] = {KVM_GENERIC_VM_STATS (),STATS_DESC_ICOUNTER (VM , pages),STATS_DESC_ICOUNTER (VM , hugepages),
arch/mips/kvm/mips.c +2 -2
@@ -38,7 +38,7 @@#define VECTORSPACING 0x100/* for EI/VI mode */ #endif -const struct _kvm_stats_desc kvm_vm_stats_desc[] = { +const struct kvm_stats_desc kvm_vm_stats_desc[] = {KVM_GENERIC_VM_STATS () };
@@ -51,7 +51,7 @@ const struct kvm_stats_header kvm_vm_sta sizeof(kvm_vm_stats_desc), }; -const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = { +const struct kvm_stats_desc kvm_vcpu_stats_desc[] = {KVM_GENERIC_VCPU_STATS (),STATS_DESC_COUNTER (VCPU , wait_exits),STATS_DESC_COUNTER (VCPU , cache_exits),
arch/powerpc/kvm/book3s.c +2 -2
@@ -38,7 +38,7 @@/* #define EXIT_DEBUG */ -const struct _kvm_stats_desc kvm_vm_stats_desc[] = { +const struct kvm_stats_desc kvm_vm_stats_desc[] = {KVM_GENERIC_VM_STATS (),STATS_DESC_ICOUNTER (VM , num_2M_pages),STATS_DESC_ICOUNTER (VM , num_1G_pages)
@@ -53,7 +53,7 @@ const struct kvm_stats_header kvm_vm_sta sizeof(kvm_vm_stats_desc), }; -const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = { +const struct kvm_stats_desc kvm_vcpu_stats_desc[] = {KVM_GENERIC_VCPU_STATS (),STATS_DESC_COUNTER (VCPU , sum_exits),STATS_DESC_COUNTER (VCPU , mmio_exits),
arch/powerpc/kvm/booke.c +2 -2
@@ -36,7 +36,7 @@unsigned long kvmppc_booke_handlers; -const struct _kvm_stats_desc kvm_vm_stats_desc[] = { +const struct kvm_stats_desc kvm_vm_stats_desc[] = {KVM_GENERIC_VM_STATS (),STATS_DESC_ICOUNTER (VM , num_2M_pages),STATS_DESC_ICOUNTER (VM , num_1G_pages)
@@ -51,7 +51,7 @@ const struct kvm_stats_header kvm_vm_sta sizeof(kvm_vm_stats_desc), }; -const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = { +const struct kvm_stats_desc kvm_vcpu_stats_desc[] = {KVM_GENERIC_VCPU_STATS (),STATS_DESC_COUNTER (VCPU , sum_exits),STATS_DESC_COUNTER (VCPU , mmio_exits),
arch/riscv/kvm/vcpu.c +1 -1
@@ -24,7 +24,7 @@#define CREATE_TRACE_POINTS #include "trace.h" -const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = { +const struct kvm_stats_desc kvm_vcpu_stats_desc[] = {KVM_GENERIC_VCPU_STATS (),STATS_DESC_COUNTER (VCPU , ecall_exit_stat),STATS_DESC_COUNTER (VCPU , wfi_exit_stat),
arch/riscv/kvm/vm.c +1 -1
@@ -13,7 +13,7 @@#include <linux/kvm_host.h> #include <asm/kvm_mmu.h> -const struct _kvm_stats_desc kvm_vm_stats_desc[] = { +const struct kvm_stats_desc kvm_vm_stats_desc[] = {KVM_GENERIC_VM_STATS () }; static_assert(ARRAY_SIZE(kvm_vm_stats_desc) ==
arch/s390/kvm/kvm-s390.c +2 -2
@@ -64,7 +64,7 @@#define VCPU_IRQS_MAX_BUF (sizeof(struct kvm_s390_irq) * \ (KVM_MAX_VCPUS + LOCAL_IRQS)) -const struct _kvm_stats_desc kvm_vm_stats_desc[] = { +const struct kvm_stats_desc kvm_vm_stats_desc[] = {KVM_GENERIC_VM_STATS (),STATS_DESC_COUNTER (VM , inject_io),STATS_DESC_COUNTER (VM , inject_float_mchk),
@@ -90,7 +90,7 @@ const struct kvm_stats_header kvm_vm_sta sizeof(kvm_vm_stats_desc), }; -const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = { +const struct kvm_stats_desc kvm_vcpu_stats_desc[] = {KVM_GENERIC_VCPU_STATS (),STATS_DESC_COUNTER (VCPU , exit_userspace),STATS_DESC_COUNTER (VCPU , exit_null),
arch/x86/kvm/x86.c +2 -2
@@ -239,7 +239,7 @@ EXPORT_SYMBOL_FOR_KVM_INTERNAL(enable_ipbool __read_mostly enable_device_posted_irqs = true;EXPORT_SYMBOL_FOR_KVM_INTERNAL (enable_device_posted_irqs); -const struct _kvm_stats_desc kvm_vm_stats_desc[] = { +const struct kvm_stats_desc kvm_vm_stats_desc[] = {KVM_GENERIC_VM_STATS (),STATS_DESC_COUNTER (VM , mmu_shadow_zapped),STATS_DESC_COUNTER (VM , mmu_pte_write),
@@ -265,7 +265,7 @@ const struct kvm_stats_header kvm_vm_sta sizeof(kvm_vm_stats_desc), }; -const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = { +const struct kvm_stats_desc kvm_vcpu_stats_desc[] = {KVM_GENERIC_VCPU_STATS (),STATS_DESC_COUNTER (VCPU , pf_taken),STATS_DESC_COUNTER (VCPU , pf_fixed),
include/linux/kvm_host.h +35 -48
107 lines not on this page · raw message
include/uapi/linux/kvm.h +8 -0
@@ -14,6 +14,10 @@#include <linux/ioctl.h> #include <asm/kvm.h> +#ifdef __KERNEL__ +#include <linux/kvm_types.h> +#endif +#define KVM_API_VERSION 12/*
@@ -1579,7 +1583,11 @@ struct kvm_stats_desc {__u16 size;__u32 offset;__u32 bucket_size; +#ifdef __KERNEL__ +char name[KVM_STATS_NAME_SIZE ]; +#else char name[]; +#endif };#define KVM_GET_STATS_FD _IO(KVMIO, 0xce)
virt/kvm/binary_stats.c +1 -1
@@ -50,7 +50,7 @@* Return: the number of bytes that has been successfully read */ ssize_t kvm_stats_read (char *id,const struct kvm_stats_header *header, -const struct _kvm_stats_desc *desc, +const struct kvm_stats_desc *desc,void *stats,size_t size_stats,char __user *user_buffer,size_t size,loff_t *offset) {
virt/kvm/kvm_main.c +10 -10
@@ -983,9 +983,9 @@ static void kvm_free_memslots(struct kvmkvm_free_memslot (kvm, memslot); } -static umode_t kvm_stats_debugfs_mode (const struct _kvm_stats_desc *pdesc) +static umode_t kvm_stats_debugfs_mode (const struct kvm_stats_desc *desc) { -switch (pdesc->desc.flags &KVM_STATS_TYPE_MASK ) { +switch (desc->flags &KVM_STATS_TYPE_MASK ) {case KVM_STATS_TYPE_INSTANT :return 0444 ;case KVM_STATS_TYPE_CUMULATIVE :
@@ -1020,7 +1020,7 @@ static int kvm_create_vm_debugfs(structstruct dentry *dent;char dir_name[ITOA_MAX_LEN *2 ];struct kvm_stat_data *stat_data; -const struct _kvm_stats_desc *pdesc; +const struct kvm_stats_desc *pdesc;int i, ret = -ENOMEM ;int kvm_debugfs_num_entries = kvm_vm_stats_header.num_desc + kvm_vcpu_stats_header.num_desc;
@@ -6186,11 +6186,11 @@ static int kvm_stat_data_get(void *data,switch (stat_data->kind) {case KVM_STAT_VM : r =kvm_get_stat_per_vm (stat_data->kvm, - stat_data->desc->desc.offset, val); + stat_data->desc->offset, val);break ;case KVM_STAT_VCPU : r =kvm_get_stat_per_vcpu (stat_data->kvm, - stat_data->desc->desc.offset, val); + stat_data->desc->offset, val);break ; }
@@ -6208,11 +6208,11 @@ static int kvm_stat_data_clear(void *datswitch (stat_data->kind) {case KVM_STAT_VM : r =kvm_clear_stat_per_vm (stat_data->kvm, - stat_data->desc->desc.offset); + stat_data->desc->offset);break ;case KVM_STAT_VCPU : r =kvm_clear_stat_per_vcpu (stat_data->kvm, - stat_data->desc->desc.offset); + stat_data->desc->offset);break ; }
@@ -6360,7 +6360,7 @@ static void kvm_uevent_notify_change(unsstatic void kvm_init_debug (void ) {const struct file_operations *fops; -const struct _kvm_stats_desc *pdesc; +const struct kvm_stats_desc *pdesc;int i; kvm_debugfs_dir =debugfs_create_dir ("kvm" ,NULL );
@@ -6373,7 +6373,7 @@ static void kvm_init_debug(void) fops = &vm_stat_readonly_fops;debugfs_create_file (pdesc->name,kvm_stats_debugfs_mode (pdesc), kvm_debugfs_dir, - (void *)(long )pdesc->desc.offset, fops); + (void *)(long )pdesc->offset, fops); }for (i =0 ; i < kvm_vcpu_stats_header.num_desc; ++i) {
@@ -6384,7 +6384,7 @@ static void kvm_init_debug(void) fops = &vcpu_stat_readonly_fops;debugfs_create_file (pdesc->name,kvm_stats_debugfs_mode (pdesc), kvm_debugfs_dir, - (void *)(long )pdesc->desc.offset, fops); + (void *)(long )pdesc->offset, fops); } }
Greg Kroah-Hartman
maintainerPATCH 196/220 KVM: x86: Use __DECLARE_FLEX_ARRAY() for UAPI structures with VLAs
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Woodhouse <[email protected]>
[ Upstream commit 2619da73bb2f10d88f7e1087125c40144fdf0987 ]
Commit 94dfc73e7cf4 ("treewide: uapi: Replace zero-length arrays with flexible-array members") broke the userspace API for C++.
These structures ending in VLAs are typically a *header*, which can be followed by an arbitrary number of entries. Userspace typically creates a larger structure with some non-zero number of entries, for example in QEMU's kvm_arch_get_supported_msr_feature():
struct {
struct kvm_msrs info;
struct kvm_msr_entry entries[1];
} msr_data = {};While that works in C, it fails in C++ with an error like:
flexible array member 'kvm_msrs::entries' not at end of 'struct msr_data'
Fix this by using __DECLARE_FLEX_ARRAY() for the VLA, which uses [0] for C++ compilation.
--- arch/x86/include/uapi/asm/kvm.h | 12 ++++++------ include/uapi/linux/kvm.h | 11 ++++++----- 2 files changed, 12 insertions(+), 11 deletions(-)
arch/x86/include/uapi/asm/kvm.h +6 -6
@@ -197,13 +197,13 @@ struct kvm_msrs {__u32 nmsrs;/* number of msrs in entries */ __u32 pad; -struct kvm_msr_entry entries[]; + __DECLARE_FLEX_ARRAY(struct kvm_msr_entry, entries); };/* for KVM_GET_MSR_INDEX_LIST */ struct kvm_msr_list {__u32 nmsrs;/* number of msrs in entries */ -__u32 indices[]; + __DECLARE_FLEX_ARRAY(__u32, indices); };/* Maximum size of any access bitmap in bytes */
@@ -245,7 +245,7 @@ struct kvm_cpuid_entry {struct kvm_cpuid {__u32 nent;__u32 padding; -struct kvm_cpuid_entry entries[]; + __DECLARE_FLEX_ARRAY(struct kvm_cpuid_entry, entries); };struct kvm_cpuid_entry2 {
@@ -267,7 +267,7 @@ struct kvm_cpuid_entry2 {struct kvm_cpuid2 {__u32 nent;__u32 padding; -struct kvm_cpuid_entry2 entries[]; + __DECLARE_FLEX_ARRAY(struct kvm_cpuid_entry2, entries); };/* for KVM_GET_PIT and KVM_SET_PIT */
@@ -398,7 +398,7 @@ struct kvm_xsave {* the contents of CPUID leaf 0xD on the host. */ __u32 region[1024 ]; -__u32 extra[]; +__DECLARE_FLEX_ARRAY (__u32, extra); };#define KVM_MAX_XCRS 16
@@ -565,7 +565,7 @@ struct kvm_pmu_event_filter {__u32 fixed_counter_bitmap;__u32 flags;__u32 pad[4 ]; -__u64 events[]; +__DECLARE_FLEX_ARRAY (__u64, events); };#define KVM_PMU_EVENT_ALLOW 0
include/uapi/linux/kvm.h +6 -5
@@ -11,6 +11,7 @@#include <linux/const.h> #include <linux/types.h> #include <linux/compiler.h> +#include <linux/stddef.h> #include <linux/ioctl.h> #include <asm/kvm.h>
@@ -532,7 +533,7 @@ struct kvm_coalesced_mmio {struct kvm_coalesced_mmio_ring {__u32 first, last; -struct kvm_coalesced_mmio coalesced_mmio[]; + __DECLARE_FLEX_ARRAY(struct kvm_coalesced_mmio, coalesced_mmio); };#define KVM_COALESCED_MMIO_MAX \
@@ -582,7 +583,7 @@ struct kvm_clear_dirty_log {/* for KVM_SET_SIGNAL_MASK */ struct kvm_signal_mask {__u32 len; -__u8 sigset[]; + __DECLARE_FLEX_ARRAY(__u8, sigset); };/* for KVM_TPR_ACCESS_REPORTING */
@@ -1040,7 +1041,7 @@ struct kvm_irq_routing_entry {struct kvm_irq_routing {__u32 nr;__u32 flags; -struct kvm_irq_routing_entry entries[]; + __DECLARE_FLEX_ARRAY(struct kvm_irq_routing_entry, entries); };#define KVM_IRQFD_FLAG_DEASSIGN (1 << 0)
@@ -1131,7 +1132,7 @@ struct kvm_dirty_tlb {struct kvm_reg_list {__u64 n;/* number of regs */ -__u64 reg[]; + __DECLARE_FLEX_ARRAY(__u64, reg); };struct kvm_one_reg {
@@ -1586,7 +1587,7 @@ struct kvm_stats_desc {#ifdef __KERNEL__char name[KVM_STATS_NAME_SIZE ];#else -char name[]; +__DECLARE_FLEX_ARRAY (char, name);#endif };
Greg Kroah-Hartman
maintainerPATCH 197/220 ocfs2: validate inline data i_size during inode read
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Deepanshu Kartikey <[email protected]>
[ Upstream commit 1524af3685b35feac76662cc551cbc37bd14775f ]
When reading an inode from disk, ocfs2_validate_inode_block() performs various sanity checks but does not validate the size of inline data. If the filesystem is corrupted, an inode's i_size can exceed the actual inline data capacity (id_count).
This causes ocfs2_dir_foreach_blk_id() to iterate beyond the inline data buffer, triggering a use-after-free when accessing directory entries from freed memory.
In the syzbot report:
- i_size was 1099511627576 bytes (~1TB)
- Actual inline data capacity (id_count) is typically <256 bytes
- A garbage rec_len (54648) caused ctx->pos to jump out of bounds
- This triggered a UAF in ocfs2_check_dir_entry()
Fix by adding a validation check in ocfs2_validate_inode_block() to ensure inodes with inline data have i_size <= id_count. This catches the corruption early during inode read and prevents all downstream code from operating on invalid data.
Stable-dep-of: 7bc5da4842be ("ocfs2: fix out-of-bounds write in ocfs2_write_end_inline")
--- fs/ocfs2/inode.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-)
fs/ocfs2/inode.c +19 -6
@@ -1494,12 +1494,25 @@ int ocfs2_validate_inode_block(struct su goto bail; } -if ((le16_to_cpu (di->i_dyn_features) &OCFS2_INLINE_DATA_FL ) && -le32_to_cpu (di->i_clusters)) { - rc =ocfs2_error (sb,"Invalid dinode %llu: %u clusters\n" , - (unsigned long long )bh->b_blocknr, -le32_to_cpu (di->i_clusters)); - goto bail; +if (le16_to_cpu (di->i_dyn_features) &OCFS2_INLINE_DATA_FL ) { +struct ocfs2_inline_data *data = &di->id2.i_data; + +if (le32_to_cpu (di->i_clusters)) { + rc =ocfs2_error (sb, +"Invalid dinode %llu: %u clusters\n" , + (unsigned long long )bh->b_blocknr, +le32_to_cpu (di->i_clusters)); + goto bail; + } + +if (le64_to_cpu (di->i_size) >le16_to_cpu (data->id_count)) { + rc =ocfs2_error (sb, +"Invalid dinode #%llu: inline data i_size %llu exceeds id_count %u\n" , + (unsigned long long )bh->b_blocknr, + (unsigned long long )le64_to_cpu (di->i_size), +le16_to_cpu (data->id_count)); + goto bail; + } }if (le32_to_cpu (di->i_flags) &OCFS2_CHAIN_FL ) {
Greg Kroah-Hartman
maintainerPATCH 198/220 ocfs2: fix out-of-bounds write in ocfs2_write_end_inline
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Joseph Qi <[email protected]>
[ Upstream commit 7bc5da4842bed3252d26e742213741a4d0ac1b14 ]
KASAN reports a use-after-free write of 4086 bytes in ocfs2_write_end_inline, called from ocfs2_write_end_nolock during a copy_file_range splice fallback on a corrupted ocfs2 filesystem mounted on a loop device. The actual bug is an out-of-bounds write past the inode block buffer, not a true use-after-free. The write overflows into an adjacent freed page, which KASAN reports as UAF.
The root cause is that ocfs2_try_to_write_inline_data trusts the on-disk id_count field to determine whether a write fits in inline data. On a corrupted filesystem, id_count can exceed the physical maximum inline data capacity, causing writes to overflow the inode block buffer.
Call trace (crash path):
vfs_copy_file_range (fs/read_write.c:1634)
do_splice_direct
splice_direct_to_actor
iter_file_splice_write
ocfs2_file_write_iter
generic_perform_write
ocfs2_write_end
ocfs2_write_end_nolock (fs/ocfs2/aops.c:1949)
ocfs2_write_end_inline (fs/ocfs2/aops.c:1915)
memcpy_from_folio <-- KASAN: write OOBSo add id_count upper bound check in ocfs2_validate_inode_block() to alongside the existing i_size check to fix it.
--- fs/ocfs2/inode.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
fs/ocfs2/inode.c +10 -0
@@ -1505,6 +1505,16 @@ int ocfs2_validate_inode_block(struct su goto bail; } +if (le16_to_cpu (data->id_count) > +ocfs2_max_inline_data_with_xattr (sb, di)) { + rc =ocfs2_error (sb, +"Invalid dinode #%llu: inline data id_count %u exceeds max %d\n" , + (unsigned long long )bh->b_blocknr, +le16_to_cpu (data->id_count), +ocfs2_max_inline_data_with_xattr (sb, di)); + goto bail; + } +if (le64_to_cpu (di->i_size) >le16_to_cpu (data->id_count)) { rc = ocfs2_error(sb, "Invalid dinode #%llu: inline data i_size %llu exceeds id_count %u\n",
Greg Kroah-Hartman
maintainerPATCH 199/220 checkpatch: add support for Assisted-by tag
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sasha Levin <[email protected]>
commit d1db4118489fffd2b2f612140b7acbb477880839 upstream.
The Assisted-by tag was introduced in Documentation/process/coding-assistants.rst for attributing AI tool contributions to kernel patches. However, checkpatch.pl did not recognize this tag, causing two issues:
WARNING: Non-standard signature: Assisted-by:
ERROR: Unrecognized email address: 'AGENT_NAME:MODEL_VERSION'
Fix this by:
1. Adding Assisted-by to the recognized $signature_tags list
2. Skipping email validation for Assisted-by lines since they use the AGENT_NAME:MODEL_VERSION format instead of an email address
3. Warning when the Assisted-by value doesn't match the expected format
--- scripts/checkpatch.pl | 10 ++++++++++ 1 file changed, 10 insertions(+)
scripts/checkpatch.pl +10 -0
@@ -641,6 +641,7 @@ our $signature_tags = qr{(?xi: Reviewed-by:| Reported-by:| Suggested-by:| + Assisted-by:| To:| Cc: )};
@@ -3091,6 +3092,15 @@ sub process { } } + # Assisted-by uses AGENT_NAME:MODEL_VERSION format, not email + if ($sign_off =~ /^Assisted-by:/i) { + if ($email !~ /^\S+:\S+/) { + WARN("BAD_SIGN_OFF", + "Assisted-by expects 'AGENT_NAME:MODEL_VERSION [TOOL1] [TOOL2]' format\n" . $herecurr); + } + next; + } + my ($email_name, $name_comment, $email_address, $comment) = parse_email($email); my $suggested_email = format_email(($email_name, $name_comment, $email_address, $comment)); if ($suggested_email eq "") {
Greg Kroah-Hartman
maintainerPATCH 200/220 x86-64: rename misleadingly named __copy_user_nocache() function
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linus Torvalds <[email protected]>
commit d187a86de793f84766ea40b9ade7ac60aabbb4fe upstream.
This function was a masterclass in bad naming, for various historical reasons.
It claimed to be a non-cached user copy. It is literally _neither_ of those things. It's a specialty memory copy routine that uses non-temporal stores for the destination (but not the source), and that does exception handling for both source and destination accesses.
Also note that while it works for unaligned targets, any unaligned parts (whether at beginning or end) will not use non-temporal stores, since only words and quadwords can be non-temporal on x86.
The exception handling means that it _can_ be used for user space accesses, but not on its own - it needs all the normal "start user space access" logic around it.
But typically the user space access would be the source, not the non-temporal destination. That was the original intention of this, where the destination was some fragile persistent memory target that needed non-temporal stores in order to catch machine check exceptions synchronously and deal with them gracefully.
Thus that non-descriptive name: one use case was to copy from user space into a non-cached kernel buffer. However, the existing users are a mix of that intended use-case, and a couple of random drivers that just did this as a performance tweak.
Some of those random drivers then actively misused the user copying version (with STAC/CLAC and all) to do kernel copies without ever even caring about the exception handling, _just_ for the non-temporal destination.
Rename it as a first small step to actually make it halfway sane, and change the prototype to be more normal: it doesn't take a user pointer unless the caller has done the proper conversion, and the argument size is the full size_t (it still won't actually copy more than 4GB in one go, but there's also no reason to silently truncate the size argument in the caller).
Finally, use this now sanely named function in the NTB code, which mis-used a user copy version (with STAC/CLAC and all) of this interface despite it not actually being a user copy at all.
--- arch/x86/include/asm/uaccess_64.h | 5 +++-- arch/x86/lib/copy_user_uncached_64.S | 6 +++--- arch/x86/lib/usercopy_64.c | 4 ++-- drivers/infiniband/sw/rdmavt/qp.c | 8 +++----- drivers/ntb/ntb_transport.c | 7 ++++--- tools/objtool/check.c | 2 +- 6 files changed, 16 insertions(+), 16 deletions(-)
arch/x86/include/asm/uaccess_64.h +3 -2
@@ -147,7 +147,8 @@ raw_copy_to_user(void __user *dst, constreturn copy_user_generic ((__force void *)dst, src, size); } -extern long __copy_user_nocache (void *dst,const void __user *src,unsigned size); +#define copy_to_nontemporal copy_to_nontemporal +extern size_t copy_to_nontemporal (void *dst,const void *src,size_t size);extern long __copy_user_flushcache (void *dst,const void __user *src,unsigned size); static inline int
@@ -157,7 +158,7 @@ __copy_from_user_inatomic_nocache(void *long ret;kasan_check_write (dst, size);stac (); - ret =__copy_user_nocache (dst, src, size); + ret =copy_to_nontemporal (dst, (__force const void *)src, size);clac ();return ret; }
arch/x86/lib/copy_user_uncached_64.S +3 -3
@@ -27,7 +27,7 @@ * Output: * rax uncopied bytes or 0 if successful. */ -SYM_FUNC_START(__copy_user_nocache) +SYM_FUNC_START(copy_to_nontemporal) ANNOTATE_NOENDBR /* If destination is not 7-byte aligned, we'll have to align it */ testb $7,%dil
@@ -240,5 +240,5 @@ _ASM_EXTABLE_UA(95b, .Ldone) _ASM_EXTABLE_UA(52b, .Ldone0) _ASM_EXTABLE_UA(53b, .Ldone0) -SYM_FUNC_END(__copy_user_nocache) -EXPORT_SYMBOL(__copy_user_nocache) +SYM_FUNC_END(copy_to_nontemporal) +EXPORT_SYMBOL(copy_to_nontemporal)
arch/x86/lib/usercopy_64.c +2 -2
@@ -49,11 +49,11 @@ long __copy_user_flushcache(void *dst, clong rc;stac (); - rc =__copy_user_nocache (dst, src, size); + rc =copy_to_nontemporal (dst, (__force const void *)src, size);clac ();/* -* __copy_user_nocache() uses non-temporal stores for the bulk +* copy_to_nontemporal() uses non-temporal stores for the bulk * of the transfer, but we need to manually flush if the * transfer is unaligned. A cached memory copy is used when * destination or size is not naturally aligned. That is:
drivers/infiniband/sw/rdmavt/qp.c +3 -5
@@ -92,12 +92,10 @@ static int rvt_wss_llc_size(void)static void cacheless_memcpy (void *dst,void *src,size_t n) {/* -* Use the only available X64 cacheless copy. Add a __user cast -* to quiet sparse. The src agument is already in the kernel so -* there are no security issues. The extra fault recovery machinery -* is not invoked. +* Use the only available X64 cacheless copy. +* The extra fault recovery machinery is not invoked. */ -__copy_user_nocache (dst, (void __user *)src, n); +copy_to_nontemporal (dst, src, n); }void rvt_wss_exit (struct rvt_dev_info *rdi)
drivers/ntb/ntb_transport.c +4 -3
@@ -1810,12 +1810,13 @@ static void ntb_tx_copy_callback(void *dstatic void ntb_memcpy_tx (struct ntb_queue_entry *entry,void __iomem *offset) { -#ifdef ARCH_HAS_NOCACHE_UACCESS +#ifdef copy_to_nontemporal/* * Using non-temporal mov to improve performance on non-cached -* writes, even though we aren't actually copying from user space. +* writes. This only works if __iomem is strictly memory-like, +* but that is the case on x86-64 */ -__copy_from_user_inatomic_nocache (offset, entry->buf, entry->len); +copy_to_nontemporal (offset, entry->buf, entry->len);#else memcpy_toio (offset, entry->buf, entry->len);#endif
tools/objtool/check.c +1 -1
@@ -1261,7 +1261,7 @@ static const char *uaccess_safe_builtin["copy_mc_enhanced_fast_string" ,"rep_stos_alternative" ,"rep_movs_alternative" , -"__copy_user_nocache" , +"copy_to_nontemporal" , NULL };
Greg Kroah-Hartman
maintainerPATCH 201/220 x86: rename and clean up __copy_from_user_inatomic_nocache()
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linus Torvalds <[email protected]>
commit 5de7bcaadf160c1716b20a263cf8f5b06f658959 upstream.
Similarly to the previous commit, this renames the somewhat confusingly named function. But in this case, it was at least less confusing: the __copy_from_user_inatomic_nocache is indeed copying from user memory, and it is indeed ok to be used in an atomic context, so it will not warn about it.
But the previous commit also removed the NTB mis-use of the __copy_from_user_inatomic_nocache() function, and as a result every call-site is now _actually_ doing a real user copy. That means that we can now do the proper user pointer verification too.
End result: add proper address checking, remove the double underscores, and change the "nocache" to "nontemporal" to more accurately describe what this x86-only function actually does. It might be worth noting that only the target is non-temporal: the actual user accesses are normal memory accesses.
Also worth noting is that non-x86 targets (and on older 32-bit x86 CPU's before XMM2 in the Pentium III) we end up just falling back on a regular user copy, so nothing can actually depend on the non-temporal semantics, but that has always been true.
--- arch/x86/include/asm/uaccess.h | 2 +- arch/x86/include/asm/uaccess_32.h | 8 +------- arch/x86/include/asm/uaccess_64.h | 3 ++- arch/x86/lib/usercopy_32.c | 9 +++++---- drivers/gpu/drm/i915/i915_gem.c | 2 +- drivers/gpu/drm/qxl/qxl_ioctl.c | 2 +- include/linux/uaccess.h | 11 ++++++++--- lib/iov_iter.c | 2 +- 8 files changed, 20 insertions(+), 19 deletions(-)
arch/x86/include/asm/uaccess.h +1 -1
@@ -507,7 +507,7 @@ extern struct movsl_mask { } ____cacheline_aligned_in_smp movsl_mask;#endif -#define ARCH_HAS_NOCACHE_UACCESS 1 +#define ARCH_HAS_NONTEMPORAL_UACCESS 1/* * The "unsafe" user accesses aren't really "unsafe", but the naming
arch/x86/include/asm/uaccess_32.h +1 -7
@@ -26,13 +26,7 @@ raw_copy_from_user(void *to, const voidreturn __copy_user_ll (to, (__force const void *)from, n); } -static __always_inline unsigned long -__copy_from_user_inatomic_nocache (void *to,const void __user *from, -unsigned long n) -{ -return __copy_from_user_ll_nocache_nozero (to, from, n); -} - +unsigned long __must_check copy_from_user_inatomic_nontemporal (void *,const void __user *,unsigned long n);unsigned long __must_check clear_user (void __user *mem,unsigned long len);unsigned long __must_check __clear_user (void __user *mem,unsigned long len);
arch/x86/include/asm/uaccess_64.h +2 -1
@@ -152,11 +152,12 @@ extern size_t copy_to_nontemporal(void *extern long __copy_user_flushcache (void *dst,const void __user *src,unsigned size);static inline int -__copy_from_user_inatomic_nocache (void *dst,const void __user *src, +copy_from_user_inatomic_nontemporal (void *dst,const void __user *src,unsigned size) {long ret;kasan_check_write (dst, size); + src =mask_user_address (src);stac (); ret =copy_to_nontemporal (dst, (__force const void *)src, size);clac ();
arch/x86/lib/usercopy_32.c +5 -4
@@ -322,10 +322,11 @@ unsigned long __copy_user_ll(void *to, c }EXPORT_SYMBOL (__copy_user_ll); -unsigned long __copy_from_user_ll_nocache_nozero (void *to,const void __user *from, +unsigned long copy_from_user_inatomic_nontemporal (void *to,const void __user *from,unsigned long n) { -__uaccess_begin_nospec (); +if (!user_access_begin (from, n)) +return n;#ifdef CONFIG_X86_INTEL_USERCOPY if (n >64 &&static_cpu_has (X86_FEATURE_XMM2 )) n =__copy_user_intel_nocache (to, from, n);
@@ -334,7 +335,7 @@ unsigned long __copy_from_user_ll_nocach#else __copy_user (to, from, n);#endif -__uaccess_end (); +user_access_end ();return n; } -EXPORT_SYMBOL (__copy_from_user_ll_nocache_nozero); +EXPORT_SYMBOL (copy_from_user_inatomic_nontemporal);
drivers/gpu/drm/i915/i915_gem.c +1 -1
@@ -520,7 +520,7 @@ ggtt_write(struct io_mapping *mapping,/* We can use the cpu mem copy function because this is X86. */ vaddr =io_mapping_map_atomic_wc (mapping, base); - unwritten =__copy_from_user_inatomic_nocache ((void __force *)vaddr + offset, + unwritten =copy_from_user_inatomic_nontemporal ((void __force *)vaddr + offset, user_data, length);io_mapping_unmap_atomic (vaddr);if (unwritten) {
drivers/gpu/drm/qxl/qxl_ioctl.c +1 -1
@@ -184,7 +184,7 @@ static int qxl_process_single_command(st/* TODO copy slow path code from i915 */ fb_cmd =qxl_bo_kmap_atomic_page (qdev, cmd_bo, (release->release_offset &PAGE_MASK )); - unwritten =__copy_from_user_inatomic_nocache + unwritten =copy_from_user_inatomic_nontemporal (fb_cmd +sizeof (union qxl_release_info ) + (release->release_offset & ~PAGE_MASK ),u64_to_user_ptr (cmd->command), cmd->command_size);
include/linux/uaccess.h +8 -3
@@ -331,16 +331,21 @@ static inline size_t probe_subpage_write#endif /* CONFIG_ARCH_HAS_SUBPAGE_FAULTS */ -#ifndef ARCH_HAS_NOCACHE_UACCESS +#ifndef ARCH_HAS_NONTEMPORAL_UACCESS static inline __must_check unsigned long -__copy_from_user_inatomic_nocache (void *to,const void __user *from, +copy_from_user_inatomic_nontemporal (void *to,const void __user *from,unsigned long n) { +if (can_do_masked_user_access ()) + from =mask_user_address (from); +else +if (!access_ok (from, n)) +return n;return __copy_from_user_inatomic (to, from, n); } -#endif /* ARCH_HAS_NOCACHE_UACCESS */ +#endif /* ARCH_HAS_NONTEMPORAL_UACCESS */ extern __must_check int check_zeroed_user (const void __user *from,size_t size);
lib/iov_iter.c +1 -1
@@ -277,7 +277,7 @@ static __always_inlinesize_t copy_from_user_iter_nocache (void __user *iter_from,size_t progress,size_t len,void *to,void *priv2) { -return __copy_from_user_inatomic_nocache (to + progress, iter_from, len); +return copy_from_user_inatomic_nontemporal (to + progress, iter_from, len); }size_t _copy_from_iter_nocache (void *addr,size_t bytes,struct iov_iter *i)
Greg Kroah-Hartman
maintainerPATCH 202/220 x86-64/arm64/powerpc: clean up and rename __copy_from_user_flushcache
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linus Torvalds <[email protected]>
commit 809b997a5ce945ab470f70c187048fe4f5df20bf upstream.
This finishes the work on these odd functions that were only implemented by a handful of architectures.
The 'flushcache' function was only used from the iterator code, and let's make it do the same thing that the nontemporal version does:
remove the two underscores and add the user address checking.
Yes, yes, the user address checking is also done at iovec import time, but we have long since walked away from the old double-underscore thing where we try to avoid address checking overhead at access time, and these functions shouldn't be so special and old-fashioned.
The arm64 version already did the address check, in fact, so there it's just a matter of renaming it. For powerpc and x86-64 we now do the proper user access boilerplate.
--- arch/arm64/include/asm/uaccess.h | 2 +- arch/powerpc/include/asm/uaccess.h | 3 +-- arch/powerpc/lib/pmem.c | 11 ++++++----- arch/x86/include/asm/uaccess_64.h | 8 ++++---- arch/x86/lib/usercopy_64.c | 8 ++++---- lib/iov_iter.c | 2 +- 6 files changed, 17 insertions(+), 17 deletions(-)
arch/arm64/include/asm/uaccess.h +1 -1
@@ -480,7 +480,7 @@ extern __must_check long strnlen_user(co#ifdef CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE extern unsigned long __must_check __copy_user_flushcache (void *to,const void __user *from,unsigned long n); -static inline int __copy_from_user_flushcache (void *dst,const void __user *src,unsigned size) +static inline size_t copy_from_user_flushcache (void *dst,const void __user *src,size_t size) {kasan_check_write (dst, size);return __copy_user_flushcache (dst,__uaccess_mask_ptr (src), size);
arch/powerpc/include/asm/uaccess.h +1 -2
@@ -407,8 +407,7 @@ copy_mc_to_user(void __user *to, const v }#endif -extern long __copy_from_user_flushcache (void *dst,const void __user *src, -unsigned size); +extern size_t copy_from_user_flushcache (void *dst,const void __user *src,size_t size); static __must_check __always_inline bool user_access_begin(const void __user *ptr, size_t len) {
arch/powerpc/lib/pmem.c +6 -5
@@ -66,15 +66,16 @@ EXPORT_SYMBOL_GPL(arch_invalidate_pmem);/* * CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE symbols */ -long __copy_from_user_flushcache (void *dest,const void __user *src, -unsigned size) +size_t copy_from_user_flushcache (void *dest,const void __user *src, +size_t size) { -unsigned long copied, start = (unsigned long ) dest; +unsigned long not_copied, start = (unsigned long ) dest; - copied =__copy_from_user (dest, src, size); + src =mask_user_address (src); + not_copied =__copy_from_user (dest, src, size);clean_pmem_range (start, start + size); -return copied; +return not_copied; }void memcpy_flushcache (void *dest,const void *src,size_t size)
arch/x86/include/asm/uaccess_64.h +4 -4
@@ -149,7 +149,7 @@ raw_copy_to_user(void __user *dst, const#define copy_to_nontemporal copy_to_nontemporalextern size_t copy_to_nontemporal (void *dst,const void *src,size_t size); -extern long __copy_user_flushcache (void *dst,const void __user *src,unsigned size); +extern size_t copy_user_flushcache (void *dst,const void __user *src,size_t size); static inline int copy_from_user_inatomic_nontemporal(void *dst, const void __user *src,
@@ -164,11 +164,11 @@ copy_from_user_inatomic_nontemporal(voidreturn ret; } -static inline int -__copy_from_user_flushcache (void *dst,const void __user *src,unsigned size) +static inline size_t +copy_from_user_flushcache (void *dst,const void __user *src,size_t size) {kasan_check_write (dst, size); -return __copy_user_flushcache (dst, src, size); +return copy_user_flushcache (dst, src, size); }/*
arch/x86/lib/usercopy_64.c +4 -4
@@ -43,14 +43,14 @@ void arch_wb_cache_pmem(void *addr, size }EXPORT_SYMBOL_GPL (arch_wb_cache_pmem); -long __copy_user_flushcache (void *dst,const void __user *src,unsigned size) +size_t copy_user_flushcache (void *dst,const void __user *src,size_t size) {unsigned long flushed, dest = (unsigned long ) dst; -long rc; +unsigned long rc; -stac (); + src =masked_user_access_begin (src); rc =copy_to_nontemporal (dst, (__force const void *)src, size); -clac (); +user_access_end ();/* * copy_to_nontemporal() uses non-temporal stores for the bulk
lib/iov_iter.c +1 -1
@@ -296,7 +296,7 @@ static __always_inlinesize_t copy_from_user_iter_flushcache (void __user *iter_from,size_t progress,size_t len,void *to,void *priv2) { -return __copy_from_user_flushcache (to + progress, iter_from, len); +return copy_from_user_flushcache (to + progress, iter_from, len); } static __always_inline
Greg Kroah-Hartman
maintainerPATCH 203/220 KVM: x86: Use scratch field in MMIO fragment to hold small write values
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sean Christopherson <[email protected]>
commit 0b16e69d17d8c35c5c9d5918bf596c75a44655d3 upstream.
When exiting to userspace to service an emulated MMIO write, copy the to-be-written value to a scratch field in the MMIO fragment if the size of the data payload is 8 bytes or less, i.e. can fit in a single chunk, instead of pointing the fragment directly at the source value.
This fixes a class of use-after-free bugs that occur when the emulator initiates a write using an on-stack, local variable as the source, the write splits a page boundary, *and* both pages are MMIO pages. Because KVM's ABI only allows for physically contiguous MMIO requests, accesses that split MMIO pages are separated into two fragments, and are sent to userspace one at a time. When KVM attempts to complete userspace MMIO in response to KVM_RUN after the first fragment, KVM will detect the second fragment and generate a second userspace exit, and reference the on-stack variable.
The issue is most visible if the second KVM_RUN is performed by a separate task, in which case the stack of the initiating task can show up as truly freed data.
==================================================================
BUG: KASAN: use-after-free in complete_emulated_mmio+0x305/0x420
Read of size 1 at addr ffff888009c378d1 by task syz-executor417/984
CPU: 1 PID: 984 Comm: syz-executor417 Not tainted 5.10.0-182.0.0.95.h2627.eulerosv2r13.x86_64 #3
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.15.0-0-g2dd4b9b3f840-prebuilt.qemu.org 04/01/2014 Call Trace:
dump_stack+0xbe/0xfd
print_address_description.constprop.0+0x19/0x170
__kasan_report.cold+0x6c/0x84
kasan_report+0x3a/0x50
check_memory_region+0xfd/0x1f0
memcpy+0x20/0x60
complete_emulated_mmio+0x305/0x420
kvm_arch_vcpu_ioctl_run+0x63f/0x6d0
kvm_vcpu_ioctl+0x413/0xb20
__se_sys_ioctl+0x111/0x160
do_syscall_64+0x30/0x40
entry_SYSCALL_64_after_hwframe+0x67/0xd1
RIP: 0033:0x42477d
Code: <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 b0 ff ff ff f7 d8 64 89 01 48
RSP: 002b:00007faa8e6890e8 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
RAX: ffffffffffffffda RBX: 00000000004d7338 RCX: 000000000042477d
RDX: 0000000000000000 RSI: 000000000000ae80 RDI: 0000000000000005
RBP: 00000000004d7330 R08: 00007fff28d546df R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000246 R12: 00000000004d733c
R13: 0000000000000000 R14: 000000000040a200 R15: 00007fff28d54720
The buggy address belongs to the page:
page:0000000029f6a428 refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x9c37
flags: 0xfffffc0000000(node=0|zone=1|lastcpupid=0x1fffff)
raw: 000fffffc0000000 0000000000000000 ffffea0000270dc8 0000000000000000
raw: 0000000000000000 0000000000000000 00000000ffffffff 0000000000000000 page dumped because: kasan: bad access detected
Memory state around the buggy address:
ffff888009c37780: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ffff888009c37800: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
>ffff888009c37880: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
^
ffff888009c37900: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ffff888009c37980: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
==================================================================The bug can also be reproduced with a targeted KVM-Unit-Test by hacking KVM to fill a large on-stack variable in complete_emulated_mmio(), i.e. by overwrite the data value with garbage.
Limit the use of the scratch fields to 8-byte or smaller accesses, and to just writes, as larger accesses and reads are not affected thanks to implementation details in the emulator, but add a sanity check to ensure those details don't change in the future. Specifically, KVM never uses on-stack variables for accesses larger that 8 bytes, e.g. uses an operand in the emulator context, and *all* reads are buffered through the mem_read cache.
Note! Using the scratch field for reads is not only unnecessary, it's also extremely difficult to handle correctly. As above, KVM buffers all reads through the mem_read cache, and heavily relies on that behavior when re-emulating the instruction after a userspace MMIO read exit. If a read splits a page, the first page is NOT an MMIO page, and the second page IS an MMIO page, then the MMIO fragment needs to point at _just_ the second chunk of the destination, i.e. its position in the mem_read cache. Taking the "obvious" approach of copying the fragment value into the destination when re-emulating the instruction would clobber the first chunk of the destination, i.e. would clobber the data that was read from guest memory.
--- arch/x86/kvm/x86.c | 14 +++++++++++++- include/linux/kvm_host.h | 3 ++- 2 files changed, 15 insertions(+), 2 deletions(-)
arch/x86/kvm/x86.c +13 -1
@@ -8214,7 +8214,13 @@ static int emulator_read_write_onepage(uWARN_ON (vcpu->mmio_nr_fragments >=KVM_MAX_MMIO_FRAGMENTS ); frag = &vcpu->mmio_fragments[vcpu->mmio_nr_fragments++]; frag->gpa = gpa; - frag->data = val; +if (write && bytes <=8u ) { + frag->val =0 ; + frag->data = &frag->val; +memcpy (&frag->val, val, bytes); + }else { + frag->data = val; + } frag->len = bytes;return X86EMUL_CONTINUE ; }
@@ -8229,6 +8235,9 @@ static int emulator_read_write(struct x8gpa_t gpa;int rc; +if (WARN_ON_ONCE ((bytes >8u || !ops->write) &&object_is_on_stack (val))) +return X86EMUL_UNHANDLEABLE ; +if (ops->read_write_prepare && ops->read_write_prepare (vcpu, val, bytes))return X86EMUL_CONTINUE ;
@@ -11834,6 +11843,9 @@ static int complete_emulated_mmio(struct frag++; vcpu->mmio_cur_fragment++; }else { +if (WARN_ON_ONCE (frag->data == &frag->val)) +return -EIO ; +/* Go forward to the next mmio piece. */ frag->data += len; frag->gpa += len;
include/linux/kvm_host.h +2 -1
@@ -320,7 +320,8 @@ static inline bool kvm_vcpu_can_poll(ktistruct kvm_mmio_fragment {gpa_t gpa;void *data; -unsigned len; +u64 val; +unsigned int len; };struct kvm_vcpu {
Greg Kroah-Hartman
maintainerPATCH 204/220 ASoC: qcom: q6apm: move component registration to unmanaged version
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Srinivas Kandagatla <[email protected]>
commit 6ec1235fc941dac6c011b30ee01d9220ff87e0cd upstream.
q6apm component registers dais dynamically from ASoC toplology, which are allocated using device managed version apis. Allocating both component and dynamic dais using managed version could lead to incorrect free ordering, dai will be freed while component still holding references to it.
Fix this issue by moving component to unmanged version so that the dai pointers are only freeded after the component is removed.
==================================================================
BUG: KASAN: slab-use-after-free in snd_soc_del_component_unlocked+0x3d4/0x400 [snd_soc_core] Read of size 8 at addr ffff00084493a6e8 by task kworker/u48:0/3426 Tainted: [W]=WARN Hardware name: LENOVO 21N2ZC5PUS/21N2ZC5PUS, BIOS N42ET57W (1.31 ) 08/08/2024 Workqueue: pdr_notifier_wq pdr_notifier_work [pdr_interface] Call trace: show_stack+0x28/0x7c (C) dump_stack_lvl+0x60/0x80 print_report+0x160/0x4b4 kasan_report+0xac/0xfc __asan_report_load8_noabort+0x20/0x34 snd_soc_del_component_unlocked+0x3d4/0x400 [snd_soc_core] snd_soc_unregister_component_by_driver+0x50/0x88 [snd_soc_core] devm_component_release+0x30/0x5c [snd_soc_core] devres_release_all+0x13c/0x210 device_unbind_cleanup+0x20/0x190 device_release_driver_internal+0x350/0x468 device_release_driver+0x18/0x30 bus_remove_device+0x1a0/0x35c device_del+0x314/0x7f0 device_unregister+0x20/0xbc apr_remove_device+0x5c/0x7c [apr] device_for_each_child+0xd8/0x160 apr_pd_status+0x7c/0xa8 [apr] pdr_notifier_work+0x114/0x240 [pdr_interface] process_one_work+0x500/0xb70 worker_thread+0x630/0xfb0 kthread+0x370/0x6c0 ret_from_fork+0x10/0x20 Allocated by task 77: kasan_save_stack+0x40/0x68 kasan_save_track+0x20/0x40 kasan_save_alloc_info+0x44/0x58 __kasan_kmalloc+0xbc/0xdc __kmalloc_node_track_caller_noprof+0x1f4/0x620 devm_kmalloc+0x7c/0x1c8 snd_soc_register_dai+0x50/0x4f0 [snd_soc_core] soc_tplg_pcm_elems_load+0x55c/0x1eb8 [snd_soc_core] snd_soc_tplg_component_load+0x4f8/0xb60 [snd_soc_core] audioreach_tplg_init+0x124/0x1fc [snd_q6apm] q6apm_audio_probe+0x10/0x1c [snd_q6apm] snd_soc_component_probe+0x5c/0x118 [snd_soc_core] soc_probe_component+0x44c/0xaf0 [snd_soc_core] snd_soc_bind_card+0xad0/0x2370 [snd_soc_core] snd_soc_register_card+0x3b0/0x4c0 [snd_soc_core] devm_snd_soc_register_card+0x50/0xc8 [snd_soc_core] x1e80100_platform_probe+0x208/0x368 [snd_soc_x1e80100] platform_probe+0xc0/0x188 really_probe+0x188/0x804 __driver_probe_device+0x158/0x358 driver_probe_device+0x60/0x190 __device_attach_driver+0x16c/0x2a8 bus_for_each_drv+0x100/0x194 __device_attach+0x174/0x380 device_initial_probe+0x14/0x20 bus_probe_device+0x124/0x154 deferred_probe_work_func+0x140/0x220 process_one_work+0x500/0xb70 worker_thread+0x630/0xfb0 kthread+0x370/0x6c0 ret_from_fork+0x10/0x20 Freed by task 3426: kasan_save_stack+0x40/0x68 kasan_save_track+0x20/0x40 __kasan_save_free_info+0x4c/0x80 __kasan_slab_free+0x78/0xa0 kfree+0x100/0x4a4 devres_release_all+0x144/0x210 device_unbind_cleanup+0x20/0x190 device_release_driver_internal+0x350/0x468 device_release_driver+0x18/0x30 bus_remove_device+0x1a0/0x35c device_del+0x314/0x7f0 device_unregister+0x20/0xbc apr_remove_device+0x5c/0x7c [apr] device_for_each_child+0xd8/0x160 apr_pd_status+0x7c/0xa8 [apr] pdr_notifier_work+0x114/0x240 [pdr_interface] process_one_work+0x500/0xb70 worker_thread+0x630/0xfb0 kthread+0x370/0x6c0 ret_from_fork+0x10/0x20
--- sound/soc/qcom/qdsp6/q6apm.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-)
sound/soc/qcom/qdsp6/q6apm.c +12 -2
@@ -744,13 +744,22 @@ static int apm_probe(gpr_device_t *gdev)q6apm_get_apm_state (apm); - ret =devm_snd_soc_register_component (dev, &q6apm_audio_component,NULL ,0 ); + ret =snd_soc_register_component (dev, &q6apm_audio_component,NULL ,0 );if (ret <0 ) {dev_err (dev,"failed to register q6apm: %d\n" , ret);return ret; } -return of_platform_populate (dev->of_node,NULL ,NULL , dev); + ret =of_platform_populate (dev->of_node,NULL ,NULL , dev); +if (ret) +snd_soc_unregister_component (dev); + +return ret; +} + +static void apm_remove (gpr_device_t *gdev) +{ +snd_soc_unregister_component (&gdev->dev); }struct audioreach_module *q6apm_find_module_by_mid (struct q6apm_graph *graph,uint32_t mid)
@@ -817,6 +826,7 @@ MODULE_DEVICE_TABLE(of, apm_device_id);static gpr_driver_t apm_driver = { .probe = apm_probe, + .remove = apm_remove, .gpr_callback = apm_callback, .driver = { .name ="qcom-apm" ,
Greg Kroah-Hartman
maintainerPATCH 205/220 mm/kasan: fix double free for kasan pXds
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ritesh Harjani (IBM) <[email protected]>
commit 51d8c78be0c27ddb91bc2c0263941d8b30a47d3b upstream.
kasan_free_pxd() assumes the page table is always struct page aligned. But that's not always the case for all architectures. E.g. In case of powerpc with 64K pagesize, PUD table (of size 4096) comes from slab cache named pgtable-2^9. Hence instead of page_to_virt(pxd_page()) let's just directly pass the start of the pxd table which is passed as the 1st argument.
This fixes the below double free kasan issue seen with PMEM:
radix-mmu: Mapped 0x0000047d10000000-0x0000047f90000000 with 2.00 MiB pages
==================================================================
BUG: KASAN: double-free in kasan_remove_zero_shadow+0x9c4/0xa20
Free of addr c0000003c38e0000 by task ndctl/2164
CPU: 34 UID: 0 PID: 2164 Comm: ndctl Not tainted 6.19.0-rc1-00048-gea1013c15392 #157 VOLUNTARY Hardware name: IBM,9080-HEX POWER10 (architected) 0x800200 0xf000006 of:IBM,FW1060.00 (NH1060_012) hv:phyp pSeries Call Trace: dump_stack_lvl+0x88/0xc4 (unreliable) print_report+0x214/0x63c kasan_report_invalid_free+0xe4/0x110 check_slab_allocation+0x100/0x150 kmem_cache_free+0x128/0x6e0 kasan_remove_zero_shadow+0x9c4/0xa20 memunmap_pages+0x2b8/0x5c0 devm_action_release+0x54/0x70 release_nodes+0xc8/0x1a0 devres_release_all+0xe0/0x140 device_unbind_cleanup+0x30/0x120 device_release_driver_internal+0x3e4/0x450 unbind_store+0xfc/0x110 drv_attr_store+0x78/0xb0 sysfs_kf_write+0x114/0x140 kernfs_fop_write_iter+0x264/0x3f0 vfs_write+0x3bc/0x7d0 ksys_write+0xa4/0x190 system_call_exception+0x190/0x480 system_call_vectored_common+0x15c/0x2ec ---- interrupt: 3000 at 0x7fff93b3d3f4 NIP: 00007fff93b3d3f4 LR: 00007fff93b3d3f4 CTR: 0000000000000000 REGS: c0000003f1b07e80 TRAP: 3000 Not tainted (6.19.0-rc1-00048-gea1013c15392) MSR: 800000000280f033 <SF,VEC,VSX,EE,PR,FP,ME,IR,DR,RI,LE> CR: 48888208 XER: 00000000
<...>
NIP [00007fff93b3d3f4] 0x7fff93b3d3f4
LR [00007fff93b3d3f4] 0x7fff93b3d3f4
---- interrupt: 3000
The buggy address belongs to the object at c0000003c38e0000 which belongs to the cache pgtable-2^9 of size 4096 The buggy address is located 0 bytes inside of 4096-byte region [c0000003c38e0000, c0000003c38e1000) The buggy address belongs to the physical page: page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x3c38c head: order:2 mapcount:0 entire_mapcount:0 nr_pages_mapped:0 pincount:0 memcg:c0000003bfd63e01 flags: 0x63ffff800000040(head|node=6|zone=0|lastcpupid=0x7ffff) page_type: f5(slab) raw: 063ffff800000040 c000000140058980 5deadbeef0000122 0000000000000000 raw: 0000000000000000 0000000080200020 00000000f5000000 c0000003bfd63e01 head: 063ffff800000040 c000000140058980 5deadbeef0000122 0000000000000000 head: 0000000000000000 0000000080200020 00000000f5000000 c0000003bfd63e01 head: 063ffff800000002 c00c000000f0e301 00000000ffffffff 00000000ffffffff head: ffffffffffffffff 0000000000000000 00000000ffffffff 0000000000000004 page dumped because: kasan: bad access detected
[ 138.953636] [ T2164] Memory state around the buggy address: [ 138.953643] [ T2164] c0000003c38dff00: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 138.953652] [ T2164] c0000003c38dff80: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 138.953661] [ T2164] >c0000003c38e0000: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 138.953669] [ T2164] ^ [ 138.953675] [ T2164] c0000003c38e0080: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 138.953684] [ T2164] c0000003c38e0100: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 138.953692] [ T2164] ================================================================== [ 138.953701] [ T2164] Disabling lock debugging due to kernel taint
--- mm/kasan/init.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
mm/kasan/init.c +4 -4
@@ -292,7 +292,7 @@ static void kasan_free_pte(pte_t *pte_streturn ; } -pte_free_kernel (&init_mm, (pte_t *)page_to_virt (pmd_page (*pmd))); +pte_free_kernel (&init_mm, pte_start);pmd_clear (pmd); }
@@ -307,7 +307,7 @@ static void kasan_free_pmd(pmd_t *pmd_streturn ; } -pmd_free (&init_mm, (pmd_t *)page_to_virt (pud_page (*pud))); +pmd_free (&init_mm, pmd_start);pud_clear (pud); }
@@ -322,7 +322,7 @@ static void kasan_free_pud(pud_t *pud_streturn ; } -pud_free (&init_mm, (pud_t *)page_to_virt (p4d_page (*p4d))); +pud_free (&init_mm, pud_start);p4d_clear (p4d); }
@@ -337,7 +337,7 @@ static void kasan_free_p4d(p4d_t *p4d_streturn ; } -p4d_free (&init_mm, (p4d_t *)page_to_virt (pgd_page (*pgd))); +p4d_free (&init_mm, p4d_start);pgd_clear (pgd); }
Greg Kroah-Hartman
maintainerPATCH 206/220 mm: blk-cgroup: fix use-after-free in cgwb_release_workfn()
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Breno Leitao <[email protected]>
commit 8f5857be99f1ed1fa80991c72449541f634626ee upstream.
cgwb_release_workfn() calls css_put(wb->blkcg_css) and then later accesses wb->blkcg_css again via blkcg_unpin_online(). If css_put() drops the last reference, the blkcg can be freed asynchronously (css_free_rwork_fn -> blkcg_css_free -> kfree) before blkcg_unpin_online() dereferences the pointer to access blkcg->online_pin, resulting in a use-after-free:
BUG: KASAN: slab-use-after-free in blkcg_unpin_online (./include/linux/instrumented.h:112 ./include/linux/atomic/atomic-instrumented.h:400 ./include/linux/refcount.h:389 ./include/linux/refcount.h:432 ./include/linux/refcount.h:450 block/blk-cgroup.c:1367)
Write of size 4 at addr ff11000117aa6160 by task kworker/71:1/531
Workqueue: cgwb_release cgwb_release_workfn
Call Trace:
<TASK>
blkcg_unpin_online (./include/linux/instrumented.h:112 ./include/linux/atomic/atomic-instrumented.h:400 ./include/linux/refcount.h:389 ./include/linux/refcount.h:432 ./include/linux/refcount.h:450 block/blk-cgroup.c:1367)
cgwb_release_workfn (mm/backing-dev.c:629)
process_scheduled_works (kernel/workqueue.c:3278 kernel/workqueue.c:3385)
Freed by task 1016:
kfree (./include/linux/kasan.h:235 mm/slub.c:2689 mm/slub.c:6246 mm/slub.c:6561)
css_free_rwork_fn (kernel/cgroup/cgroup.c:5542)
process_scheduled_works (kernel/workqueue.c:3302 kernel/workqueue.c:3385)** Stack based on commit 66672af7a095 ("Add linux-next specific files for 20260410")
I am seeing this crash sporadically in Meta fleet across multiple kernel versions. A full reproducer is available at:
https://github.com/leitao/debug/blob/main/reproducers/repro_blkcg_uaf.sh
(The race window is narrow. To make it easily reproducible, inject a msleep(100) between css_put() and blkcg_unpin_online() in cgwb_release_workfn(). With that delay and a KASAN-enabled kernel, the reproducer triggers the splat reliably in less than a second.)
Fix this by moving blkcg_unpin_online() before css_put(), so the cgwb's CSS reference keeps the blkcg alive while blkcg_unpin_online() accesses it.
--- mm/backing-dev.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
mm/backing-dev.c +3 -2
@@ -618,12 +618,13 @@ static void cgwb_release_workfn(struct wwb_shutdown (wb);css_put (wb->memcg_css); -css_put (wb->blkcg_css); -mutex_unlock (&wb->bdi->cgwb_release_mutex);/* triggers blkg destruction if no online users left */ blkcg_unpin_online (wb->blkcg_css); +css_put (wb->blkcg_css); +mutex_unlock (&wb->bdi->cgwb_release_mutex); +fprop_local_destroy_percpu (&wb->memcg_completions);spin_lock_irq (&cgwb_lock);
Greg Kroah-Hartman
maintainerPATCH 207/220 media: vidtv: fix nfeeds state corruption on start_streaming failure
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ruslan Valiyev <[email protected]>
commit a0e5a598fe9a4612b852406b51153b881592aede upstream.
syzbot reported a memory leak in vidtv_psi_service_desc_init [1].
When vidtv_start_streaming() fails inside vidtv_start_feed(), the nfeeds counter is left incremented even though no feed was actually started. This corrupts the driver state: subsequent start_feed calls see nfeeds > 1 and skip starting the mux, while stop_feed calls eventually try to stop a non-existent stream.
This state corruption can also lead to memory leaks, since the mux and channel resources may be partially allocated during a failed start_streaming but never cleaned up, as the stop path finds dvb->streaming == false and returns early.
Fix by decrementing nfeeds back when start_streaming fails, keeping the counter in sync with the actual number of active feeds.
[1]
BUG: memory leak unreferenced object 0xffff888145b50820 (size 32): comm "syz.0.17", pid 6068, jiffies 4294944486 backtrace (crc 90a0c7d4): vidtv_psi_service_desc_init+0x74/0x1b0 drivers/media/test-drivers/vidtv/vidtv_psi.c:288 vidtv_channel_s302m_init+0xb1/0x2a0 drivers/media/test-drivers/vidtv/vidtv_channel.c:83 vidtv_channels_init+0x1b/0x40 drivers/media/test-drivers/vidtv/vidtv_channel.c:524 vidtv_mux_init+0x516/0xbe0 drivers/media/test-drivers/vidtv/vidtv_mux.c:518 vidtv_start_streaming drivers/media/test-drivers/vidtv/vidtv_bridge.c:194 [inline] vidtv_start_feed+0x33e/0x4d0 drivers/media/test-drivers/vidtv/vidtv_bridge.c:239
--- drivers/media/test-drivers/vidtv/vidtv_bridge.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/media/test-drivers/vidtv/vidtv_bridge.c +3 -1
@@ -237,8 +237,10 @@ static int vidtv_start_feed(struct dvb_dif (dvb->nfeeds ==1 ) { ret =vidtv_start_streaming (dvb); -if (ret <0 ) +if (ret <0 ) { + dvb->nfeeds--; rc = ret; + } }mutex_unlock (&dvb->feed_lock);
Greg Kroah-Hartman
maintainerPATCH 208/220 media: mediatek: vcodec: fix use-after-free in encoder release path
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fan Wu <[email protected]>
commit 76e35091ffc722ba39b303e48bc5d08abb59dd56 upstream.
The fops_vcodec_release() function frees the context structure (ctx) without first cancelling any pending or running work in ctx->encode_work. This creates a race window where the workqueue handler (mtk_venc_worker) may still be accessing the context memory after it has been freed.
Race condition:
CPU 0 (release path) CPU 1 (workqueue)
--------------------- ------------------
fops_vcodec_release()
v4l2_m2m_ctx_release()
v4l2_m2m_cancel_job()
// waits for m2m job "done"
mtk_venc_worker()
v4l2_m2m_job_finish()
// m2m job "done"
// BUT worker still running!
// post-job_finish access:
other ctx dereferences
// UAF if ctx already freed
// returns (job "done")
kfree(ctx) // ctx freedRoot cause: The v4l2_m2m_ctx_release() only waits for the m2m job lifecycle (via TRANS_RUNNING flag), not the workqueue lifecycle. After v4l2_m2m_job_finish() is called, the m2m framework considers the job complete and v4l2_m2m_ctx_release() returns, but the worker function continues executing and may still access ctx.
The work is queued during encode operations via:
queue_work(ctx->dev->encode_workqueue, &ctx->encode_work)
The worker function accesses ctx->m2m_ctx, ctx->dev, and other ctx fields even after calling v4l2_m2m_job_finish().
This vulnerability was confirmed with KASAN by running an instrumented test module that widens the post-job_finish race window. KASAN detected:
BUG: KASAN: slab-use-after-free in mtk_venc_worker+0x159/0x180
Read of size 4 at addr ffff88800326e000 by task kworker/u8:0/12
Workqueue: mtk_vcodec_enc_wq mtk_venc_worker
Allocated by task 47:
__kasan_kmalloc+0x7f/0x90
fops_vcodec_open+0x85/0x1a0
Freed by task 47:
__kasan_slab_free+0x43/0x70
kfree+0xee/0x3a0
fops_vcodec_release+0xb7/0x190Fix this by calling cancel_work_sync(&ctx->encode_work) before kfree(ctx). This ensures the workqueue handler is both cancelled (if pending) and synchronized (waits for any running handler to complete) before the context is freed.
Placement rationale: The fix is placed after v4l2_ctrl_handler_free() and before list_del_init(&ctx->list). At this point, all m2m operations are done (v4l2_m2m_ctx_release() has returned), and we need to ensure the workqueue is synchronized before removing ctx from the list and freeing it.
Note: The open error path does NOT need cancel_work_sync() because INIT_WORK() only initializes the work structure - it does not schedule it. Work is only scheduled later during device_run() operations.
--- drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.c | 9 +++++++++ 1 file changed, 9 insertions(+)
drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.c +9 -0
@@ -215,6 +215,15 @@ static int fops_vcodec_release(struct fiv4l2_fh_exit (&ctx->fh);v4l2_ctrl_handler_free (&ctx->ctrl_hdl); +/* +* Cancel any pending encode work before freeing the context. +* Although v4l2_m2m_ctx_release() waits for m2m job completion, +* the workqueue handler (mtk_venc_worker) may still be accessing +* the context after v4l2_m2m_job_finish() returns. Without this, +* a use-after-free occurs when the worker accesses ctx after kfree. +*/ +cancel_work_sync (&ctx->encode_work); +spin_lock_irqsave (&dev->dev_ctx_lock, flags);list_del_init (&ctx->list);spin_unlock_irqrestore (&dev->dev_ctx_lock, flags);
Greg Kroah-Hartman
maintainerPATCH 209/220 media: em28xx: fix use-after-free in em28xx_v4l2_open()
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Abhishek Kumar <[email protected]>
commit a66485a934c7187ae8e36517d40615fa2e961cff upstream.
em28xx_v4l2_open() reads dev->v4l2 without holding dev->lock, creating a race with em28xx_v4l2_init()'s error path and em28xx_v4l2_fini(), both of which free the em28xx_v4l2 struct and set dev->v4l2 to NULL under dev->lock.
This race leads to two issues:
- use-after-free in v4l2_fh_init() when accessing vdev->ctrl_handler, since the video_device is embedded in the freed em28xx_v4l2 struct.
- NULL pointer dereference in em28xx_resolution_set() when accessing v4l2->norm, since dev->v4l2 has been set to NULL.
Fix this by moving the mutex_lock() before the dev->v4l2 read and adding a NULL check for dev->v4l2 under the lock.
--- drivers/media/usb/em28xx/em28xx-video.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-)
drivers/media/usb/em28xx/em28xx-video.c +10 -4
@@ -2126,7 +2126,7 @@ static int em28xx_v4l2_open(struct file {struct video_device *vdev =video_devdata (filp);struct em28xx *dev =video_drvdata (filp); -struct em28xx_v4l2 *v4l2 = dev->v4l2; +struct em28xx_v4l2 *v4l2;enum v4l2_buf_type fh_type =0 ;int ret;
@@ -2143,13 +2143,19 @@ static int em28xx_v4l2_open(struct filereturn -EINVAL ; } +if (mutex_lock_interruptible (&dev->lock)) +return -ERESTARTSYS ; + + v4l2 = dev->v4l2; +if (!v4l2) { +mutex_unlock (&dev->lock); +return -ENODEV ; + } +em28xx_videodbg ("open dev=%s type=%s users=%d\n" ,video_device_node_name (vdev), v4l2_type_names[fh_type], v4l2->users); -if (mutex_lock_interruptible (&dev->lock)) -return -ERESTARTSYS ; - ret =v4l2_fh_open (filp);if (ret) { dev_err(&dev->intf->dev,
Greg Kroah-Hartman
maintainerPATCH 210/220 hwmon: (powerz) Fix use-after-free on USB disconnect
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sanman Pradhan <[email protected]>
commit 08e57f5e1a9067d5fbf33993aa7f51d60b3d13a4 upstream.
After powerz_disconnect() frees the URB and releases the mutex, a subsequent powerz_read() call can acquire the mutex and call powerz_read_data(), which dereferences the freed URB pointer.
Fix by:
- Setting priv->urb to NULL in powerz_disconnect() so that powerz_read_data() can detect the disconnected state.
- Adding a !priv->urb check at the start of powerz_read_data() to return -ENODEV on a disconnected device.
- Moving usb_set_intfdata() before hwmon registration so the disconnect handler can always find the priv pointer.
--- drivers/hwmon/powerz.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
drivers/hwmon/powerz.c +6 -2
@@ -108,6 +108,9 @@ static int powerz_read_data(struct usb_d {int ret; +if (!priv->urb) +return -ENODEV ; + priv->status = -ETIMEDOUT ;reinit_completion (&priv->completion);
@@ -224,6 +227,8 @@ static int powerz_probe(struct usb_intermutex_init (&priv->mutex);init_completion (&priv->completion); +usb_set_intfdata (intf, priv); + hwmon_dev =devm_hwmon_device_register_with_info (parent,DRIVER_NAME , priv, &powerz_chip_info,NULL );
@@ -232,8 +237,6 @@ static int powerz_probe(struct usb_interreturn PTR_ERR (hwmon_dev); } -usb_set_intfdata (intf, priv); -return 0 ; }
@@ -244,6 +247,7 @@ static void powerz_disconnect(struct usbmutex_lock (&priv->mutex);usb_kill_urb (priv->urb);usb_free_urb (priv->urb); + priv->urb =NULL ;mutex_unlock (&priv->mutex); }
Greg Kroah-Hartman
maintainerPATCH 211/220 ALSA: 6fire: fix use-after-free on disconnect
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Berk Cem Goksel <[email protected]>
commit b9c826916fdce6419b94eb0cd8810fdac18c2386 upstream.
In usb6fire_chip_abort(), the chip struct is allocated as the card's private data (via snd_card_new with sizeof(struct sfire_chip)). When snd_card_free_when_closed() is called and no file handles are open, the card and embedded chip are freed synchronously. The subsequent chip->card = NULL write then hits freed slab memory.
Call trace: usb6fire_chip_abort sound/usb/6fire/chip.c:59 [inline] usb6fire_chip_disconnect+0x348/0x358 sound/usb/6fire/chip.c:182 usb_unbind_interface+0x1a8/0x88c drivers/usb/core/driver.c:458 ... hub_event+0x1a04/0x4518 drivers/usb/core/hub.c:5953
Fix by moving the card lifecycle out of usb6fire_chip_abort() and into usb6fire_chip_disconnect(). The card pointer is saved in a local before any teardown, snd_card_disconnect() is called first to prevent new opens, URBs are aborted while chip is still valid, and snd_card_free_when_closed() is called last so chip is never accessed after the card may be freed.
--- sound/usb/6fire/chip.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-)
sound/usb/6fire/chip.c +12 -5
@@ -53,11 +53,6 @@ static void usb6fire_chip_abort(struct susb6fire_comm_abort (chip);if (chip->control)usb6fire_control_abort (chip); -if (chip->card) { -snd_card_disconnect (chip->card); -snd_card_free_when_closed (chip->card); - chip->card =NULL ; - } } }
@@ -168,6 +163,7 @@ destroy_chip:static void usb6fire_chip_disconnect (struct usb_interface *intf) {struct sfire_chip *chip; +struct snd_card *card; chip =usb_get_intfdata (intf);if (chip) {/* if !chip, fw upload has been performed */
@@ -178,8 +174,19 @@ static void usb6fire_chip_disconnect(str chips[chip->regidx] =NULL ; } +/* +* Save card pointer before teardown. +* snd_card_free_when_closed() may free card (and +* the embedded chip) immediately, so it must be +* called last and chip must not be accessed after. +*/ + card = chip->card; chip->shutdown = true; +if (card) +snd_card_disconnect (card);usb6fire_chip_abort (chip); +if (card) +snd_card_free_when_closed (card); } } }
Greg Kroah-Hartman
maintainerPATCH 212/220 bcache: fix cached_dev.sb_bio use-after-free and crash
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mingzhe Zou <[email protected]>
commit fec114a98b8735ee89c75216c45a78e28be0f128 upstream.
In our production environment, we have received multiple crash reports regarding libceph, which have caught our attention:
``` [6888366.280350] Call Trace: [6888366.280452] blk_update_request+0x14e/0x370 [6888366.280561] blk_mq_end_request+0x1a/0x130 [6888366.280671] rbd_img_handle_request+0x1a0/0x1b0 [rbd] [6888366.280792] rbd_obj_handle_request+0x32/0x40 [rbd] [6888366.280903] __complete_request+0x22/0x70 [libceph] [6888366.281032] osd_dispatch+0x15e/0xb40 [libceph] [6888366.281164] ? inet_recvmsg+0x5b/0xd0 [6888366.281272] ? ceph_tcp_recvmsg+0x6f/0xa0 [libceph] [6888366.281405] ceph_con_process_message+0x79/0x140 [libceph] [6888366.281534] ceph_con_v1_try_read+0x5d7/0xf30 [libceph] [6888366.281661] ceph_con_workfn+0x329/0x680 [libceph] ```
After analyzing the coredump file, we found that the address of dc->sb_bio has been freed. We know that cached_dev is only freed when it is stopped.
Since sb_bio is a part of struct cached_dev, rather than an alloc every time. If the device is stopped while writing to the superblock, the released address will be accessed at endio.
This patch hopes to wait for sb_write to complete in cached_dev_free.
It should be noted that we analyzed the cause of the problem, then tell all details to the QWEN and adopted the modifications it made.
--- drivers/md/bcache/super.c | 7 +++++++ 1 file changed, 7 insertions(+)
drivers/md/bcache/super.c +7 -0
@@ -1373,6 +1373,13 @@ static CLOSURE_CALLBACK(cached_dev_free)mutex_unlock (&bch_register_lock); +/* +* Wait for any pending sb_write to complete before free. +* The sb_bio is embedded in struct cached_dev, so we must +* ensure no I/O is in progress. +*/ +closure_sync (&dc->sb_write); +if (dc->sb_disk)folio_put (virt_to_folio (dc->sb_disk));
Greg Kroah-Hartman
maintainerPATCH 213/220 wireguard: device: use exit_rtnl callback instead of manual rtnl_lock in pre_exit
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shardul Bankar <[email protected]>
commit 60a25ef8dacb3566b1a8c4de00572a498e2a3bf9 upstream.
wg_netns_pre_exit() manually acquires rtnl_lock() inside the pernet .pre_exit callback. This causes a hung task when another thread holds rtnl_mutex - the cleanup_net workqueue (or the setup_net failure rollback path) blocks indefinitely in wg_netns_pre_exit() waiting to acquire the lock.
Convert to .exit_rtnl, introduced in commit 7a60d91c690b ("net:
Add ->exit_rtnl() hook to struct pernet_operations."), where the framework already holds RTNL and batches all callbacks under a single rtnl_lock()/rtnl_unlock() pair, eliminating the contention window.
The rcu_assign_pointer(wg->creating_net, NULL) is safe to move from .pre_exit to .exit_rtnl (which runs after synchronize_rcu()) because all RCU readers of creating_net either use maybe_get_net()
- which returns NULL for a dying namespace with zero refcount - or access net->user_ns which remains valid throughout the entire ops_undo_list sequence.
--- drivers/net/wireguard/device.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-)
drivers/net/wireguard/device.c +3 -5
@@ -411,12 +411,11 @@ static struct rtnl_link_ops link_ops __r .newlink = wg_newlink, }; -static void wg_netns_pre_exit (struct net *net) +static void __net_exit wg_netns_exit_rtnl(struct net *net, struct list_head *dev_kill_list) {struct wg_device *wg;struct wg_peer *peer; -rtnl_lock ();list_for_each_entry (wg, &device_list, device_list) {if (rcu_access_pointer (wg->creating_net) == net) {pr_debug ("%s: Creating namespace exiting\n" , wg->dev->name);
@@ -429,11 +428,10 @@ static void wg_netns_pre_exit(struct netmutex_unlock (&wg->device_update_lock); } } -rtnl_unlock (); } -static struct pernet_operations pernet_ops = { - .pre_exit = wg_netns_pre_exit +static struct pernet_operations pernet_ops__read_mostly = { + .exit_rtnl = wg_netns_exit_rtnl };int __init wg_device_init (void )
Greg Kroah-Hartman
maintainerPATCH 214/220 media: as102: fix to not free memory after the device is registered in as102_usb_probe()
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jeongjun Park <[email protected]>
commit 8bd29dbe03fc5b0f039ab2395ff37b64236d2f0c upstream.
In as102_usb driver, the following race condition occurs:
```
CPU0 CPU1
as102_usb_probe()
kzalloc(); // alloc as102_dev_t
....
usb_register_dev();
fd = sys_open("/path/to/dev"); // open as102 fd
....
usb_deregister_dev();
....
kfree(); // free as102_dev_t
....
sys_close(fd);
as102_release() // UAF!!
as102_usb_release()
kfree(); // DFB!!
```When a USB character device registered with usb_register_dev() is later unregistered (via usb_deregister_dev() or disconnect), the device node is removed so new open() calls fail. However, file descriptors that are already open do not go away immediately: they remain valid until the last reference is dropped and the driver's .release() is invoked.
In as102, as102_usb_probe() calls usb_register_dev() and then, on an error path, does usb_deregister_dev() and frees as102_dev_t right away. If userspace raced a successful open() before the deregistration, that open FD will later hit as102_release() --> as102_usb_release() and access or free as102_dev_t again, occur a race to use-after-free and double-free vuln.
The fix is to never kfree(as102_dev_t) directly once usb_register_dev() has succeeded. After deregistration, defer freeing memory to .release().
In other words, let release() perform the last kfree when the final open FD is closed.
--- drivers/media/usb/as102/as102_usb_drv.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/media/usb/as102/as102_usb_drv.c +2 -0
@@ -403,7 +403,9 @@ static int as102_usb_probe(struct usb_in failed_dvb:as102_free_usb_stream_buffer (as102_dev); failed_stream: +usb_set_intfdata (intf,NULL );usb_deregister_dev (intf, &as102_usb_class_driver); +return ret; failed:usb_put_dev (as102_dev->bus_adap.usb_dev);usb_set_intfdata (intf,NULL );
Greg Kroah-Hartman
maintainerPATCH 215/220 nilfs2: fix NULL i_assoc_inode dereference in nilfs_mdt_save_to_shadow_map
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Deepanshu Kartikey <[email protected]>
commit 4a4e0328edd9e9755843787d28f16dd4165f8b48 upstream.
The DAT inode's btree node cache (i_assoc_inode) is initialized lazily during btree operations. However, nilfs_mdt_save_to_shadow_map() assumes i_assoc_inode is already initialized when copying dirty pages to the shadow map during GC.
If NILFS_IOCTL_CLEAN_SEGMENTS is called immediately after mount before any btree operation has occurred on the DAT inode, i_assoc_inode is NULL leading to a general protection fault.
Fix this by calling nilfs_attach_btree_node_cache() on the DAT inode in nilfs_dat_read() at mount time, ensuring i_assoc_inode is always initialized before any GC operation can use it.
--- fs/nilfs2/dat.c | 3 +++ 1 file changed, 3 insertions(+)
fs/nilfs2/dat.c +3 -0
@@ -524,6 +524,9 @@ int nilfs_dat_read(struct super_block *sif (err) goto failed; + err =nilfs_attach_btree_node_cache (dat); +if (err) + goto failed; err =nilfs_read_inode_common (dat, raw_inode);if (err) goto failed;
Greg Kroah-Hartman
maintainerPATCH 216/220 media: vidtv: fix pass-by-value structs causing MSAN warnings
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Abd-Alrhman Masalkhi <[email protected]>
commit 5f8e73bde67e931468bc2a1860d78d72f0c6ba41 upstream.
vidtv_ts_null_write_into() and vidtv_ts_pcr_write_into() take their argument structs by value, causing MSAN to report uninit-value warnings. While only vidtv_ts_null_write_into() has triggered a report so far, both functions share the same issue.
Fix by passing both structs by const pointer instead, avoiding the stack copy of the struct along with its MSAN shadow and origin metadata. The functions do not modify the structs, which is enforced by the const qualifier.
--- drivers/media/test-drivers/vidtv/vidtv_mux.c | 4 +- drivers/media/test-drivers/vidtv/vidtv_ts.c | 50 +++++++++++++-------------- drivers/media/test-drivers/vidtv/vidtv_ts.h | 4 +- 3 files changed, 29 insertions(+), 29 deletions(-)
drivers/media/test-drivers/vidtv/vidtv_mux.c +2 -2
@@ -233,7 +233,7 @@ static u32 vidtv_mux_push_pcr(struct vid/* the 27Mhz clock will feed both parts of the PCR bitfield */ args.pcr = m->timing.clk; - nbytes +=vidtv_ts_pcr_write_into (args); + nbytes +=vidtv_ts_pcr_write_into (&args); m->mux_buf_offset += nbytes; m->num_streamed_pcr++;
@@ -363,7 +363,7 @@ static u32 vidtv_mux_pad_with_nulls(stru args.continuity_counter = &ctx->cc;for (i =0 ; i < npkts; ++i) { - m->mux_buf_offset +=vidtv_ts_null_write_into (args); + m->mux_buf_offset +=vidtv_ts_null_write_into (&args); args.dest_offset = m->mux_buf_offset; }
drivers/media/test-drivers/vidtv/vidtv_ts.c +25 -25
97 lines not on this page · raw message
drivers/media/test-drivers/vidtv/vidtv_ts.h +2 -2
@@ -90,7 +90,7 @@ void vidtv_ts_inc_cc(u8 *continuity_coun* * Return: The number of bytes written into the buffer. */ -u32 vidtv_ts_null_write_into (struct null_packet_write_args args); +u32 vidtv_ts_null_write_into (const struct null_packet_write_args *args);/** * vidtv_ts_pcr_write_into - Write a PCR packet into a buffer.
@@ -101,6 +101,6 @@ u32 vidtv_ts_null_write_into(struct null* * Return: The number of bytes written into the buffer. */ -u32 vidtv_ts_pcr_write_into (struct pcr_write_args args); +u32 vidtv_ts_pcr_write_into (const struct pcr_write_args *args);#endif //VIDTV_TS_H
Greg Kroah-Hartman
maintainerPATCH 217/220 media: hackrf: fix to not free memory after the device is registered in hackrf_probe()
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jeongjun Park <[email protected]>
commit 3b7da2b4d0fe014eff181ed37e3bf832eb8ed258 upstream.
In hackrf driver, the following race condition occurs:
```
CPU0 CPU1
hackrf_probe()
kzalloc(); // alloc hackrf_dev
....
v4l2_device_register();
....
fd = sys_open("/path/to/dev"); // open hackrf fd
....
v4l2_device_unregister();
....
kfree(); // free hackrf_dev
....
sys_ioctl(fd, ...);
v4l2_ioctl();
video_is_registered() // UAF!!
....
sys_close(fd);
v4l2_release() // UAF!!
hackrf_video_release()
kfree(); // DFB!!
```When a V4L2 or video device is unregistered, the device node is removed so new open() calls are blocked.
However, file descriptors that are already open-and any in-flight I/O-do not terminate immediately; they remain valid until the last reference is dropped and the driver's release() is invoked.
Therefore, freeing device memory on the error path after hackrf_probe() has registered dev it will lead to a race to use-after-free vuln, since those already-open handles haven't been released yet.
And since release() free memory too, race to use-after-free and double-free vuln occur.
To prevent this, if device is registered from probe(), it should be modified to free memory only through release() rather than calling kfree() directly.
--- drivers/media/usb/hackrf/hackrf.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
drivers/media/usb/hackrf/hackrf.c +4 -3
@@ -1485,7 +1485,7 @@ static int hackrf_probe(struct usb_interif (ret) {dev_err (dev->dev,"Failed to register as video device (%d)\n" , ret); - goto err_v4l2_device_unregister; + goto err_v4l2_device_put; }dev_info (dev->dev,"Registered as %s\n" ,video_device_node_name (&dev->rx_vdev));
@@ -1513,8 +1513,9 @@ static int hackrf_probe(struct usb_interreturn 0 ; err_video_unregister_device_rx:video_unregister_device (&dev->rx_vdev); -err_v4l2_device_unregister: -v4l2_device_unregister (&dev->v4l2_dev); +err_v4l2_device_put: +v4l2_device_put (&dev->v4l2_dev); +return ret; err_v4l2_ctrl_handler_free_tx:v4l2_ctrl_handler_free (&dev->tx_ctrl_handler); err_v4l2_ctrl_handler_free_rx:
Greg Kroah-Hartman
maintainerPATCH 218/220 mm/userfaultfd: fix hugetlb fault mutex hash calculation
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jianhui Zhou <[email protected]>
commit 0217c7fb4de4a40cee667eb21901f3204effe5ac upstream.
In mfill_atomic_hugetlb(), linear_page_index() is used to calculate the page index for hugetlb_fault_mutex_hash(). However, linear_page_index() returns the index in PAGE_SIZE units, while hugetlb_fault_mutex_hash() expects the index in huge page units. This mismatch means that different addresses within the same huge page can produce different hash values, leading to the use of different mutexes for the same huge page. This can cause races between faulting threads, which can corrupt the reservation map and trigger the BUG_ON in resv_map_release().
Fix this by introducing hugetlb_linear_page_index(), which returns the page index in huge page granularity, and using it in place of linear_page_index().
--- include/linux/hugetlb.h | 17 +++++++++++++++++ mm/userfaultfd.c | 2 +- 2 files changed, 18 insertions(+), 1 deletion(-)
include/linux/hugetlb.h +17 -0
@@ -796,6 +796,23 @@ static inline unsigned huge_page_shift(sreturn h->order +PAGE_SHIFT ; } +/** +* hugetlb_linear_page_index() - linear_page_index() but in hugetlb +* page size granularity. +* @vma: the hugetlb VMA +* @address: the virtual address within the VMA +* +* Return: the page offset within the mapping in huge page units. +*/ +static inline pgoff_t hugetlb_linear_page_index (struct vm_area_struct *vma, +unsigned long address) +{ +struct hstate *h =hstate_vma (vma); + +return ((address - vma->vm_start) >>huge_page_shift (h)) + + (vma->vm_pgoff >>huge_page_order (h)); +} +static inline bool order_is_gigantic (unsigned int order) {return order >MAX_PAGE_ORDER ;
mm/userfaultfd.c +1 -1
@@ -573,7 +573,7 @@ retry:* in the case of shared pmds. fault mutex prevents * races with other faulting threads. */ - idx =linear_page_index (dst_vma, dst_addr); + idx =hugetlb_linear_page_index (dst_vma, dst_addr); mapping = dst_vma->vm_file->f_mapping; hash =hugetlb_fault_mutex_hash (mapping, idx);mutex_lock (&hugetlb_fault_mutex_table[hash]);
Greg Kroah-Hartman
maintainerPATCH 219/220 dma-debug: Allow multiple invocations of overlapping entries
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Leon Romanovsky <[email protected]>
commit eca58535b154e6951327319afda94ac80eae7dc3 upstream.
Repeated DMA mappings with DMA_ATTR_CPU_CACHE_CLEAN trigger the following splat. This prevents using the attribute in cases where a DMA region is shared and reused more than seven times.
------------[ cut here ]------------ DMA-API: exceeded 7 overlapping mappings of cacheline 0x000000000438c440 WARNING: kernel/dma/debug.c:467 at add_dma_entry+0x219/0x280, CPU#4: ibv_rc_pingpong/1644 Modules linked in: xt_conntrack xt_MASQUERADE nf_conntrack_netlink nfnetlink iptable_nat nf_nat xt_addrtype br_netfilter rpcsec_gss_krb5 auth_rpcgss oid_registry overlay mlx5_fwctl zram zsmalloc mlx5_ib fuse rpcrdma rdma_ucm ib_uverbs ib_iser libiscsi scsi_transport_iscsi ib_umad rdma_cm ib_ipoib iw_cm ib_cm mlx5_core ib_core CPU: 4 UID: 2733 PID: 1644 Comm: ibv_rc_pingpong Not tainted 6.19.0+ #129 PREEMPT Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.13.0-0-gf21b5a4aeb02-prebuilt.qemu.org 04/01/2014 RIP: 0010:add_dma_entry+0x221/0x280 Code: c0 0f 84 f2 fe ff ff 83 e8 01 89 05 6d 99 11 01 e9 e4 fe ff ff 0f 8e 1f ff ff ff 48 8d 3d 07 ef 2d 01 be 07 00 00 00 48 89 e2 <67> 48 0f b9 3a e9 06 ff ff ff 48 c7 c7 98 05 2b 82 c6 05 72 92 28 RSP: 0018:ff1100010e657970 EFLAGS: 00010002 RAX: 0000000000000007 RBX: ff1100010234eb00 RCX: 0000000000000000 RDX: ff1100010e657970 RSI: 0000000000000007 RDI: ffffffff82678660 RBP: 000000000438c440 R08: 0000000000000228 R09: 0000000000000000 R10: 00000000000001be R11: 000000000000089d R12: 0000000000000800 R13: 00000000ffffffef R14: 0000000000000202 R15: ff1100010234eb00 FS: 00007fb15f3f6740(0000) GS:ff110008dcc19000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007fb15f32d3a0 CR3: 0000000116f59001 CR4: 0000000000373eb0 Call Trace: <TASK> debug_dma_map_sg+0x1b4/0x390 __dma_map_sg_attrs+0x6d/0x1a0 dma_map_sgtable+0x19/0x30 ib_umem_get+0x284/0x3b0 [ib_uverbs] mlx5_ib_reg_user_mr+0x68/0x2a0 [mlx5_ib] ib_uverbs_reg_mr+0x17f/0x2a0 [ib_uverbs] ib_uverbs_handler_UVERBS_METHOD_INVOKE_WRITE+0xc2/0x130 [ib_uverbs] ib_uverbs_cmd_verbs+0xa0b/0xae0 [ib_uverbs] ? ib_uverbs_handler_UVERBS_METHOD_QUERY_PORT_SPEED+0xe0/0xe0 [ib_uverbs] ? mmap_region+0x7a/0xb0 ? do_mmap+0x3b8/0x5c0 ib_uverbs_ioctl+0xa7/0x110 [ib_uverbs] __x64_sys_ioctl+0x14f/0x8b0 ? ksys_mmap_pgoff+0xc5/0x190 do_syscall_64+0x8c/0xbf0 entry_SYSCALL_64_after_hwframe+0x4b/0x53 RIP: 0033:0x7fb15f5e4eed Code: 04 25 28 00 00 00 48 89 45 c8 31 c0 48 8d 45 10 c7 45 b0 10 00 00 00 48 89 45 b8 48 8d 45 d0 48 89 45 c0 b8 10 00 00 00 0f 05 <89> c2 3d 00 f0 ff ff 77 1a 48 8b 45 c8 64 48 2b 04 25 28 00 00 00 RSP: 002b:00007ffe09a5c540 EFLAGS: 00000246 ORIG_RAX: 0000000000000010 RAX: ffffffffffffffda RBX: 00007ffe09a5c5d0 RCX: 00007fb15f5e4eed RDX: 00007ffe09a5c5f0 RSI: 00000000c0181b01 RDI: 0000000000000003 RBP: 00007ffe09a5c590 R08: 0000000000000028 R09: 00007ffe09a5c794 R10: 0000000000000001 R11: 0000000000000246 R12: 00007ffe09a5c794 R13: 000000000000000c R14: 0000000025a49170 R15: 000000000000000c </TASK> ---[ end trace 0000000000000000 ]---
--- kernel/dma/debug.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
kernel/dma/debug.c +3 -3
@@ -453,7 +453,7 @@ static int active_cacheline_set_overlap(return overlap; } -static void active_cacheline_inc_overlap (phys_addr_t cln) +static void active_cacheline_inc_overlap (phys_addr_t cln,bool is_cache_clean) {int overlap =active_cacheline_read_overlap (cln);
@@ -462,7 +462,7 @@ static void active_cacheline_inc_overlap/* If we overflowed the overlap counter then we're potentially * leaking dma-mappings. */ -WARN_ONCE (overlap >ACTIVE_CACHELINE_MAX_OVERLAP , +WARN_ONCE (!is_cache_clean && overlap >ACTIVE_CACHELINE_MAX_OVERLAP ,pr_fmt ("exceeded %d overlapping mappings of cacheline %pa\n" ),ACTIVE_CACHELINE_MAX_OVERLAP , &cln); }
@@ -495,7 +495,7 @@ static int active_cacheline_insert(strucif (rc == -EEXIST ) {struct dma_debug_entry *existing; -active_cacheline_inc_overlap (cln); +active_cacheline_inc_overlap (cln, entry->is_cache_clean); existing =radix_tree_lookup (&dma_active_cacheline, cln);/* A lookup failure here after we got -EEXIST is unexpected. */ WARN_ON (!existing);
Greg Kroah-Hartman
maintainerPATCH 220/220 dma-mapping: handle DMA_ATTR_CPU_CACHE_CLEAN in trace output
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Leon Romanovsky <[email protected]>
commit 6f45b1604cf43945ef472ae4ef30354025307c19 upstream.
Tracing prints decoded DMA attribute flags, but it does not yet include the recently added DMA_ATTR_CPU_CACHE_CLEAN. Add support for decoding and displaying this attribute in the trace output.
--- include/trace/events/dma.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
include/trace/events/dma.h +2 -1
@@ -32,7 +32,8 @@ TRACE_DEFINE_ENUM(DMA_NONE); { DMA_ATTR_ALLOC_SINGLE_PAGES, "ALLOC_SINGLE_PAGES" }, \ { DMA_ATTR_NO_WARN, "NO_WARN" }, \ { DMA_ATTR_PRIVILEGED, "PRIVILEGED" }, \ - { DMA_ATTR_MMIO, "MMIO" }) + { DMA_ATTR_MMIO, "MMIO" }, \ + { DMA_ATTR_CPU_CACHE_CLEAN, "CACHE_CLEAN" }) DECLARE_EVENT_CLASS(dma_map, TP_PROTO(struct device *dev, phys_addr_t phys_addr, dma_addr_t dma_addr,
Quoted 9 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 6.19.14 release. There are 220 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Wed, 22 Apr 2026 15:38:52 +0000. Anything received after that time might be too late.
The whole patch series can be found in one patch at:
Quoted 8 lines
https://www.kernel.org/pub/linux/kernel/v6.x/stable-review/patch-6.19.14-rc1.gzor in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.gitlinux-6.19.y
and the diffstat can be found below.thanks,
greg k-h
On ARCH_BRCMSTB using 32-bit and 64-bit ARM kernels, build tested on BMIPS_GENERIC:
Signature · 1 line
Florian
Am 20.04.2026 um 17:39 schrieb Greg Kroah-Hartman:
Quoted 4 lines
This is the start of the stable review cycle for the 6.19.14 release. There are 220 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Builds, boots and works on my 2-socket Ivy Bridge Xeon E5-2697 v2 server. No dmesg oddities or regressions found.
Beste Grüße,
Peter Schneider
Signature · 8 lines
Climb the mountain not to plant your flag, but to embrace the challenge, enjoy the air and behold the view. Climb it so you can see the world, not so the world can see you. -- David McCullough Jr. OpenPGP: 0xA3828BD796CCE11A8CADE8866E3A92C92C3FF244 Download: https://www.peters-netzplatz.de/download/pschneider1968_pub.asc https://keys.mailvelope.com/pks/lookup?op=get&[email protected] https://keys.mailvelope.com/pks/lookup?op=get&[email protected]
Quoted 9 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 6.19.14 release. There are 220 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Wed, 22 Apr 2026 15:38:52 +0000. Anything received after that time might be too late.
The whole patch series can be found in one patch at:
Quoted 8 lines
https://www.kernel.org/pub/linux/kernel/v6.x/stable-review/patch-6.19.14-rc1.gzor in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.gitlinux-6.19.y
and the diffstat can be found below.thanks,
greg k-h
Built and booted successfully on RISC-V RV64 (HiFive Unmatched).
# Librecast Test Results
020/020 [ OK ] liblcrq
010/010 [ OK ] libmld
120/120 [ OK ] liblibrecast
CPU/kernel: Linux auntie 6.19.14-rc1-gd5ff99d1ccf4 #1 SMP PREEMPT_DYNAMIC Tue Apr 21 07:51:57 -00 2026 x86_64 AMD Ryzen 9 9950X 16-Core Processor AuthenticAMD GNU/Linux
Quoted 8 lines · On Mon, 20 Apr 2026 17:39:01 +0200 Greg Kroah-Hartman…
This is the start of the stable review cycle for the 6.19.14 release. There are 220 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Wed, 22 Apr 2026 15:38:52 +0000. Anything received after that time might be too late.
Boot-tested under QEMU for Rust x86_64, arm64 and riscv64; built-tested for loongarch64:
I also did a few arm 32-bit build-tests, and they look fine.
Thanks!
Cheers,
Miguel
Quoted 4 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 6.19.14 release. There are 220 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Quoted 9 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 6.19.14 release. There are 220 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Wed, 22 Apr 2026 15:38:52 +0000. Anything received after that time might be too late.
The whole patch series can be found in one patch at:
Quoted 8 lines
https://www.kernel.org/pub/linux/kernel/v6.x/stable-review/patch-6.19.14-rc1.gzor in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.gitlinux-6.19.y
and the diffstat can be found below.thanks,
greg k-h
Tested rc1 against the Fedora build system (aarch64, ppc64le, s390x, x86_64), and boot tested x86_64. No regressions noted.
Quoted 9 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 6.19.14 release. There are 220 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Wed, 22 Apr 2026 15:38:52 +0000. Anything received after that time might be too late.
The whole patch series can be found in one patch at:
Quoted 9 lines
https://www.kernel.org/pub/linux/kernel/v6.x/stable-review/patch-6.19.14-rc1.gzor in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.gitlinux-6.19.y
and the diffstat can be found below.thanks,
greg k-h
Compiled and booted on my test system. No dmesg regressions.
thanks,
-- Shuah
Quoted 9 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 6.19.14 release. There are 220 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Wed, 22 Apr 2026 15:38:52 +0000. Anything received after that time might be too late.
The whole patch series can be found in one patch at:
Quoted 8 lines
https://www.kernel.org/pub/linux/kernel/v6.x/stable-review/patch-6.19.14-rc1.gzor in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.gitlinux-6.19.y
and the diffstat can be found below.thanks,
greg k-h
I tested 6.19.14-rc1 with clockevents-prevent-timer-interrupt-starvation.patch reverted (since it has been reverted in the stable-queue) on 2 different amd64 systems. Working well, no regressions observed.
Signature · 1 line
-Barry K. Nathan <[email protected]>
Hi!
Quoted 4 lines
This is the start of the stable review cycle for the 6.19.14 release. There are 220 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
CIP testing did not find any problems here:
https://gitlab.com/cip-project/cip-testing/linux-stable-rc-ci/-/tree/linux-6.19.y
Best regards,
Pavel
Quoted 15 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 6.19.14 release. There are 220 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Wed, 22 Apr 2026 15:38:52 +0000. Anything received after that time might be too late.
The whole patch series can be found in one patch at:
https://www.kernel.org/pub/linux/kernel/v6.x/stable-review/patch-6.19.14-rc1.gzor in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.gitlinux-6.19.y
and the diffstat can be found below.
Quoted 5 lines
thanks,
greg k-h
-------------
Build and Boot Report 6.19.14-rc1
I built and tested Linux kernel version 6.19.14 using the default configurations on both x86_64 and arm64 architectures in a virtualized environment.
The kernel compiled successfully on both architectures and booted without issues.
I did not observe any regressions or new warnings in dmesg during boot.
Kernel version: 6.19.14-rc1
Configurations tested: x86_64_defconfig, defconfig
Architectures tested: x86_64, arm64
Kernel source: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.git
Commit: d5ff99d1ccf4eb2e2288c5126f1f846a8ed7e4ab
Best regards,
Dileep Malepu.