 iommu/s390: Implement blocking domain · gregkh/linux@bd89d94 · GitHub Skip to content Navigation Menu Toggle navigation Sign in Appearance settings Platform AI CODE CREATION GitHub Copilot Write better code with AI GitHub Spark Build and deploy intelligent apps GitHub Models Manage and compare prompts MCP Registry New Integrate external tools DEVELOPER WORKFLOWS Actions Automate any workflow Codespaces Instant dev environments Issues Plan and track work Code Review Manage code changes APPLICATION SECURITY GitHub Advanced Security Find and fix vulnerabilities Code security Secure your code as you build Secret protection  EXPLORE Why GitHub Documentation Blog Changelog Marketplace View all features Solutions BY COMPANY SIZE Enterprises Small and medium teams Startups Nonprofits BY USE CASE App Modernization DevSecOps DevOps CI/CD View all use cases BY INDUSTRY Healthcare Financial services Manufacturing Government View all industries View all solutions Resources EXPLORE BY TOPIC AI Software Development DevOps Security View all topics EXPLORE BY TYPE Customer stories Events &amp; webinars Ebooks &amp; reports Business insights GitHub Skills SUPPORT &amp; SERVICES Documentation Customer support Community forum Trust center Partners View all resources Open Source COMMUNITY GitHub Sponsors Fund open source developers PROGRAMS Security Lab Maintainer Community Accelerator GitHub Stars Archive Program REPOSITORIES Topics Trending Collections Enterprise ENTERPRISE SOLUTIONS Enterprise platform AI-powered developer platform AVAILABLE ADD-ONS GitHub Advanced Security Enterprise-grade security features Copilot for Business Enterprise-grade AI features Premium Support Enterprise-grade 24/7 support Pricing Search or jump to... Search code, repositories, users, issues, pull requests... --> Search Clear Search syntax tips Provide feedback --> We read every piece of feedback, and take your input very seriously.  Cancel Submit feedback Saved searches Use saved searches to filter your results more quickly --> Name Query To see all available qualifiers, see our documentation . Cancel Create saved search Sign in Sign up Appearance settings Resetting focus You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session. You switched accounts on another tab or window. Reload to refresh your session. Dismiss alert {{ message }} gregkh / linux Public Notifications You must be signed in to change notification settings Fork 686 Star 644 Code Actions Security and quality 0 Insights Additional navigation options Code Actions Security and quality Insights Commit bd89d94 Browse files Browse files rosatomj authored and gregkh committed iommu/s390: Implement blocking domain [ Upstream commit ecda483 ] This fixes a crash when surprise hot-unplugging a PCI device. This crash happens because during hot-unplug __iommu_group_set_domain_nofail() attaching the default domain fails when the platform no longer recognizes the device as it has already been removed and we end up with a NULL domain pointer and UAF. This is exactly the case referred to in the second comment in __iommu_device_set_domain() and just as stated there if we can instead attach the blocking domain the UAF is prevented as this can handle the already removed device. Implement the blocking domain to use this handling. With this change, the crash is fixed but we still hit a warning attempting to change DMA ownership on a blocked device. Fixes: c76c067 ("s390/pci: Use dma-iommu layer") Co-developed-by: Niklas Schnelle &lt;schnelle@linux.ibm.com&gt; Signed-off-by: Niklas Schnelle &lt;schnelle@linux.ibm.com&gt; Signed-off-by: Matthew Rosato &lt;mjrosato@linux.ibm.com&gt; Reviewed-by: Niklas Schnelle &lt;schnelle@linux.ibm.com&gt; Reviewed-by: Jason Gunthorpe &lt;jgg@nvidia.com&gt; Link: https://lore.kernel.org/r/20240910211516.137933-1-mjrosato@linux.ibm.com Signed-off-by: Joerg Roedel &lt;jroedel@suse.de&gt; Signed-off-by: Sasha Levin &lt;sashal@kernel.org&gt; 1 parent 89dc91e commit bd89d94 Copy full SHA for bd89d94 4 file s changed + 59 - 31 Lines changed: 59 additions &amp; 31 deletions File tree Expand file tree Collapse file tree Open diff view settings Filter options arch/s390 include/asm pci.h pci pci.c pci_debug.c drivers/iommu s390-iommu.c Expand file tree Collapse file tree Open diff view settings Collapse file ‎ arch/s390/include/asm/pci.h ‎ Copy file name to clipboard Expand all lines: arch/s390/include/asm/pci.h + 2 - 2 Lines changed: 2 additions &amp; 2 deletions Original file line number Diff line number Diff line change @@ -96,7 +96,6 @@ struct zpci_bar_struct { 96 96 u8 size ; /* order 2 exponent */ 97 97 }; 98 98 99 - struct s390_domain ; 100 99 struct kvm_zdev ; 101 100 102 101 #define ZPCI_FUNCTIONS_PER_BUS 256 @@ -181,9 +180,10 @@ struct zpci_dev { 181 180 struct dentry * debugfs_dev ; 182 181 183 182 /* IOMMU and passthrough */ 184 - struct s390_domain * s390_domain ; /* s390 IOMMU domain data */ 183 + struct iommu_domain * s390_domain ; /* attached IOMMU domain */ 185 184 struct kvm_zdev * kzdev ; 186 185 struct mutex kzdev_lock ; 186 + spinlock_t dom_lock ; /* protect s390_domain change */ 187 187 }; 188 188 189 189 static inline bool zdev_enabled ( struct zpci_dev * zdev ) Collapse file ‎ arch/s390/pci/pci.c ‎ Copy file name to clipboard Expand all lines: arch/s390/pci/pci.c + 3 Lines changed: 3 additions &amp; 0 deletions Original file line number Diff line number Diff line change @@ -160,6 +160,7 @@ int zpci_fmb_enable_device(struct zpci_dev *zdev) 160 160 u64 req = ZPCI_CREATE_REQ ( zdev -&gt; fh , 0 , ZPCI_MOD_FC_SET_MEASURE ); 161 161 struct zpci_iommu_ctrs * ctrs ; 162 162 struct zpci_fib fib = { 0 }; 163 + unsigned long flags ; 163 164 u8 cc , status ; 164 165 165 166 if ( zdev -&gt; fmb || sizeof ( * zdev -&gt; fmb ) &lt; zdev -&gt; fmb_length ) @@ -171,6 +172,7 @@ int zpci_fmb_enable_device(struct zpci_dev *zdev) 171 172 WARN_ON (( u64 ) zdev -&gt; fmb &amp; 0xf ); 172 173 173 174 /* reset software counters */ 175 + spin_lock_irqsave ( &amp; zdev -&gt; dom_lock , flags ); 174 176 ctrs = zpci_get_iommu_ctrs ( zdev ); 175 177 if ( ctrs ) { 176 178 atomic64_set ( &amp; ctrs -&gt; mapped_pages , 0 ); @@ -179,6 +181,7 @@ int zpci_fmb_enable_device(struct zpci_dev *zdev) 179 181 atomic64_set ( &amp; ctrs -&gt; sync_map_rpcits , 0 ); 180 182 atomic64_set ( &amp; ctrs -&gt; sync_rpcits , 0 ); 181 183 } 184 + spin_unlock_irqrestore ( &amp; zdev -&gt; dom_lock , flags ); 182 185 183 186 184 187 fib . fmb_addr = virt_to_phys ( zdev -&gt; fmb ); Collapse file ‎ arch/s390/pci/pci_debug.c ‎ Copy file name to clipboard Expand all lines: arch/s390/pci/pci_debug.c + 8 - 2 Lines changed: 8 additions &amp; 2 deletions Original file line number Diff line number Diff line change @@ -71,17 +71,23 @@ static void pci_fmb_show(struct seq_file *m, char *name[], int length, 71 71 72 72 static void pci_sw_counter_show ( struct seq_file * m ) 73 73 { 74 - struct zpci_iommu_ctrs * ctrs = zpci_get_iommu_ctrs ( m -&gt; private ); 74 + struct zpci_dev * zdev = m -&gt; private ; 75 + struct zpci_iommu_ctrs * ctrs ; 75 76 atomic64_t * counter ; 77 + unsigned long flags ; 76 78 int i ; 77 79 80 + spin_lock_irqsave ( &amp; zdev -&gt; dom_lock , flags ); 81 + ctrs = zpci_get_iommu_ctrs ( m -&gt; private ); 78 82 if (! ctrs ) 79 - return ; 83 + goto unlock ; 80 84 81 85 counter = &amp; ctrs -&gt; mapped_pages ; 82 86 for ( i = 0 ; i &lt; ARRAY_SIZE ( pci_sw_names ); i ++ , counter ++ ) 83 87 seq_printf ( m , &quot;%26s:\t%llu\n&quot; , pci_sw_names [ i ], 84 88 atomic64_read ( counter )); 89 + unlock : 90 + spin_unlock_irqrestore ( &amp; zdev -&gt; dom_lock , flags ); 85 91 } 86 92 87 93 static int pci_perf_show ( struct seq_file * m , void * v ) Collapse file ‎ drivers/iommu/s390-iommu.c ‎ Copy file name to clipboard Expand all lines: drivers/iommu/s390-iommu.c + 46 - 27 Lines changed: 46 additions &amp; 27 deletions Original file line number Diff line number Diff line change @@ -33,6 +33,8 @@ struct s390_domain { 33 33 struct rcu_head rcu ; 34 34 }; 35 35 36 + static struct iommu_domain blocking_domain ; 37 + 36 38 static inline unsigned int calc_rtx ( dma_addr_t ptr ) 37 39 { 38 40 return (( unsigned long ) ptr &gt;&gt; ZPCI_RT_SHIFT ) &amp; ZPCI_INDEX_MASK ; @@ -369,20 +371,36 @@ static void s390_domain_free(struct iommu_domain *domain) 369 371 call_rcu ( &amp; s390_domain -&gt; rcu , s390_iommu_rcu_free_domain ); 370 372 } 371 373 372 - static void s390_iommu_detach_device ( struct iommu_domain * domain , 373 - struct device * dev ) 374 + static void zdev_s390_domain_update ( struct zpci_dev * zdev , 375 + struct iommu_domain * domain ) 376 + { 377 + unsigned long flags ; 378 + 379 + spin_lock_irqsave ( &amp; zdev -&gt; dom_lock , flags ); 380 + zdev -&gt; s390_domain = domain ; 381 + spin_unlock_irqrestore ( &amp; zdev -&gt; dom_lock , flags ); 382 + } 383 + 384 + static int blocking_domain_attach_device ( struct iommu_domain * domain , 385 + struct device * dev ) 374 386 { 375 - struct s390_domain * s390_domain = to_s390_domain ( domain ); 376 387 struct zpci_dev * zdev = to_zpci_dev ( dev ); 388 + struct s390_domain * s390_domain ; 377 389 unsigned long flags ; 378 390 391 + if ( zdev -&gt; s390_domain -&gt; type == IOMMU_DOMAIN_BLOCKED ) 392 + return 0 ; 393 + 394 + s390_domain = to_s390_domain ( zdev -&gt; s390_domain ); 379 395 spin_lock_irqsave ( &amp; s390_domain -&gt; list_lock , flags ); 380 396 list_del_rcu ( &amp; zdev -&gt; iommu_list ); 381 397 spin_unlock_irqrestore ( &amp; s390_domain -&gt; list_lock , flags ); 382 398 383 399 zpci_unregister_ioat ( zdev , 0 ); 384 - zdev -&gt; s390_domain = NULL ; 385 400 zdev -&gt; dma_table = NULL ; 401 + zdev_s390_domain_update ( zdev , domain ); 402 + 403 + return 0 ; 386 404 } 387 405 388 406 static int s390_iommu_attach_device ( struct iommu_domain * domain , @@ -401,20 +419,15 @@ static int s390_iommu_attach_device(struct iommu_domain *domain, 401 419 domain -&gt; geometry . aperture_end &lt; zdev -&gt; start_dma )) 402 420 return - EINVAL ; 403 421 404 - if ( zdev -&gt; s390_domain ) 405 - s390_iommu_detach_device ( &amp; zdev -&gt; s390_domain -&gt; domain , dev ); 422 + blocking_domain_attach_device ( &amp; blocking_domain , dev ); 406 423 424 + /* If we fail now DMA remains blocked via blocking domain */ 407 425 cc = zpci_register_ioat ( zdev , 0 , zdev -&gt; start_dma , zdev -&gt; end_dma , 408 426 virt_to_phys ( s390_domain -&gt; dma_table ), &amp; status ); 409 - /* 410 - * If the device is undergoing error recovery the reset code 411 - * will re-establish the new domain. 412 - */ 413 427 if ( cc &amp;&amp; status != ZPCI_PCI_ST_FUNC_NOT_AVAIL ) 414 428 return - EIO ; 415 - 416 429 zdev -&gt; dma_table = s390_domain -&gt; dma_table ; 417 - zdev -&gt; s390_domain = s390_domain ; 430 + zdev_s390_domain_update ( zdev , domain ) ; 418 431 419 432 spin_lock_irqsave ( &amp; s390_domain -&gt; list_lock , flags ); 420 433 list_add_rcu ( &amp; zdev -&gt; iommu_list , &amp; s390_domain -&gt; devices ); @@ -466,19 +479,11 @@ static struct iommu_device *s390_iommu_probe_device(struct device *dev) 466 479 if ( zdev -&gt; tlb_refresh ) 467 480 dev -&gt; iommu -&gt; shadow_on_flush = 1 ; 468 481 469 - return &amp; zdev -&gt; iommu_dev ; 470 - } 482 + /* Start with DMA blocked */ 483 + spin_lock_init ( &amp; zdev -&gt; dom_lock ); 484 + zdev_s390_domain_update ( zdev , &amp; blocking_domain ); 471 485 472 - static void s390_iommu_release_device ( struct device * dev ) 473 - { 474 - struct zpci_dev * zdev = to_zpci_dev ( dev ); 475 - 476 - /* 477 - * release_device is expected to detach any domain currently attached 478 - * to the device, but keep it attached to other devices in the group. 479 - */ 480 - if ( zdev ) 481 - s390_iommu_detach_device ( &amp; zdev -&gt; s390_domain -&gt; domain , dev ); 486 + return &amp; zdev -&gt; iommu_dev ; 482 487 } 483 488 484 489 static int zpci_refresh_all ( struct zpci_dev * zdev ) @@ -697,9 +702,15 @@ static size_t s390_iommu_unmap_pages(struct iommu_domain *domain, 697 702 698 703 struct zpci_iommu_ctrs * zpci_get_iommu_ctrs ( struct zpci_dev * zdev ) 699 704 { 700 - if (! zdev || ! zdev -&gt; s390_domain ) 705 + struct s390_domain * s390_domain ; 706 + 707 + lockdep_assert_held ( &amp; zdev -&gt; dom_lock ); 708 + 709 + if ( zdev -&gt; s390_domain -&gt; type == IOMMU_DOMAIN_BLOCKED ) 701 710 return NULL ; 702 - return &amp; zdev -&gt; s390_domain -&gt; ctrs ; 711 + 712 + s390_domain = to_s390_domain ( zdev -&gt; s390_domain ); 713 + return &amp; s390_domain -&gt; ctrs ; 703 714 } 704 715 705 716 int zpci_init_iommu ( struct zpci_dev * zdev ) @@ -776,11 +787,19 @@ static int __init s390_iommu_init(void) 776 787 } 777 788 subsys_initcall ( s390_iommu_init ); 778 789 790 + static struct iommu_domain blocking_domain = { 791 + . type = IOMMU_DOMAIN_BLOCKED , 792 + . ops = &amp; ( const struct iommu_domain_ops ) { 793 + . attach_dev = blocking_domain_attach_device , 794 + } 795 + }; 796 + 779 797 static const struct iommu_ops s390_iommu_ops = { 798 + . blocked_domain = &amp; blocking_domain , 799 + . release_domain = &amp; blocking_domain , 780 800 . capable = s390_iommu_capable , 781 801 . domain_alloc_paging = s390_domain_alloc_paging , 782 802 . probe_device = s390_iommu_probe_device , 783 - . release_device = s390_iommu_release_device , 784 803 . device_group = generic_device_group , 785 804 . pgsize_bitmap = SZ_4K , 786 805 . get_resv_regions = s390_iommu_get_resv_regions , 0 commit comments Comments 0 ( 0 ) Footer &copy; 2026 GitHub,&nbsp;Inc. Footer navigation Terms Privacy Security Status Community Docs Contact Manage cookies Do not share my personal information You can’t perform that action at this time. 