Public bug reported: BugLink: https://bugs.launchpad.net/bugs/1978423
[Impact] When attempting to mount a cifs share, and it fails while the kernel is attempting to get the root inode, typically in cifs_get_root(), a double free can occur leading to a general protection fault which panics the system. For example, if we try to mount a cifs share with an out of date kerberos ticket: [ 479.783182] CIFS: Attempting to mount \\cifs-host\cifs-share [ 479.791769] CIFS: VFS: Verify user has a krb5 ticket and keyutils is installed [ 479.791774] CIFS: VFS: \\cifs-host Send error in SessSetup = -126 [ 479.791777] CIFS: VFS: cifs_read_super: get root inode failed We hit a general protection fault: [ 479.826541] general protection fault, probably for non-canonical address 0x2a8e69ddd8028c0: 0000 [#1] SMP NOPTI [ 479.826546] CPU: 9 PID: 8826 Comm: nautilus Kdump: loaded Tainted: P OE 5.11.0-40-generic #44~20.04.2-Ubuntu [ 479.826549] Hardware name: VMware, Inc. VMware7,1/440BX Desktop Reference Platform, BIOS VMW71.00V.18227214.B64.2106252220 06/25/2021 [ 479.826551] RIP: 0010:kfree+0x5d/0x420 [ 479.826574] CR2: 0000559ba2c12000 CR3: 0000002160152002 CR4: 00000000007706e0 [ 479.826597] Call Trace: [ 479.826598] <IRQ> [ 479.826603] smb3_cleanup_fs_context_contents.part.0+0x19/0xc0 [cifs] [ 479.826660] smb3_cleanup_fs_context+0x18/0x30 [cifs] [ 479.826694] delayed_free+0x1f/0x30 [cifs] [ 479.826720] rcu_core+0x32a/0x500 [ 479.826725] rcu_core_si+0xe/0x10 [ 479.826727] __do_softirq+0xe0/0x29b [ 479.826731] asm_call_irq_on_stack+0xf/0x20 [ 479.826734] </IRQ> [ 479.826735] do_softirq_own_stack+0x3d/0x50 [ 479.826739] irq_exit_rcu+0xa4/0xb0 [ 479.826743] sysvec_apic_timer_interrupt+0x3d/0x90 [ 479.826748] ? asm_sysvec_apic_timer_interrupt+0xa/0x20 [ 479.826750] asm_sysvec_apic_timer_interrupt+0x12/0x20 [ 479.826753] RIP: 0033:0x7f410e544e98 [Fix] The issue happens because we fall through a goto label, and free the same cifs_sb->ctx pointer twice. The first happens when we fall through out_super to out: 790 struct dentry * 791 cifs_smb3_do_mount(struct file_system_type *fs_type, 792 int flags, struct smb3_fs_context *old_ctx) 793 { ... 883 out_super: 884 deactivate_locked_super(sb); 885 out: 886 if (cifs_sb) { 887 kfree(cifs_sb->prepath); 888 smb3_cleanup_fs_context(cifs_sb->ctx); 889 kfree(cifs_sb); 890 } 891 return root; 892 } The second happens in deactivate_locked_super() when we eventually make way to delayed_free() after many function calls inbetween: 3779 static void delayed_free(struct rcu_head *p) 3780 { 3781 struct cifs_sb_info *cifs_sb = container_of(p, struct cifs_sb_info, rcu); 3782 3783 unload_nls(cifs_sb->local_nls); 3784 smb3_cleanup_fs_context(cifs_sb->ctx); 3785 kfree(cifs_sb); 3786 } smb3_cleanup_fs_context() frees cifs_sb->ctx, as well as all of its pointers in the struct. I came across the following mailing list discussion about a double free occurring during cifs_smb3_do_mount() when we fail to get a reference to a root dentry [2][3]. [2] https://www.spinics.net/lists/linux-cifs/msg24485.html [3] https://www.spinics.net/lists/linux-cifs/msg24486.html For the mailing list discussion, there is a patch submitted [4], and it was merged into mainline in 5.17-rc5 in the below commit: [4] https://www.spinics.net/lists/linux-cifs/msg24487.html commit 3d6cc9898efdfb062efb74dc18cfc700e082f5d5 Author: Ronnie Sahlberg <lsahl...@redhat.com> Date: Fri Feb 11 02:59:15 2022 +1000 Subject: cifs: fix double free race when mount fails in cifs_get_root() Link: https://github.com/torvalds/linux/commit/3d6cc9898efdfb062efb74dc18cfc700e082f5d5 This was fixed-released in 5.13.0-48-generic and 5.15.0-23-generic. [Testcase] Attempt to mount a cifs share where it would fail during the initial mount, e.g. attempting to mount a cifs share with kerberos authentication, with an out of date or invalid kerberos ticket. [Where problems could occur] The fix adds a return to the out_super label, to prevent fallthrough to out. All resources will still be cleaned up correctly through the call to deactivate_locked_super(), which will eventually reach delayed_free() and free the resources there, so there won't be any memory leaks of any sort that arise due to the patch. If a regression were to occur, it would affect users of cifs mounts, that error out and fail during the initial mounting stage. A workaround would be to correct the issue that prevents mount in the first place, so it would avoid the teardown code on mount failure. ** Affects: linux (Ubuntu) Importance: Undecided Status: Fix Released ** Affects: linux (Ubuntu Impish) Importance: Undecided Status: Fix Released ** Affects: linux (Ubuntu Jammy) Importance: Undecided Status: Fix Released ** Tags: sts ** Changed in: linux (Ubuntu) Status: New => Fix Released ** Also affects: linux (Ubuntu Impish) Importance: Undecided Status: New ** Also affects: linux (Ubuntu Jammy) Importance: Undecided Status: New ** Changed in: linux (Ubuntu Impish) Status: New => Fix Released ** Changed in: linux (Ubuntu Jammy) Status: New => Fix Released ** Description changed: - BugLink: https://bugs.launchpad.net/bugs/ + BugLink: https://bugs.launchpad.net/bugs/1978423 [Impact] When attempting to mount a cifs share, and it fails while the kernel is attempting to get the root inode, typically in cifs_get_root(), a double free can occur leading to a general protection fault which panics the system. For example, if we try to mount a cifs share with an out of date kerberos ticket: [ 479.783182] CIFS: Attempting to mount \\cifs-host\cifs-share [ 479.791769] CIFS: VFS: Verify user has a krb5 ticket and keyutils is installed [ 479.791774] CIFS: VFS: \\cifs-host Send error in SessSetup = -126 [ 479.791777] CIFS: VFS: cifs_read_super: get root inode failed We hit a general protection fault: [ 479.826541] general protection fault, probably for non-canonical address 0x2a8e69ddd8028c0: 0000 [#1] SMP NOPTI [ 479.826546] CPU: 9 PID: 8826 Comm: nautilus Kdump: loaded Tainted: P OE 5.11.0-40-generic #44~20.04.2-Ubuntu [ 479.826549] Hardware name: VMware, Inc. VMware7,1/440BX Desktop Reference Platform, BIOS VMW71.00V.18227214.B64.2106252220 06/25/2021 [ 479.826551] RIP: 0010:kfree+0x5d/0x420 [ 479.826574] CR2: 0000559ba2c12000 CR3: 0000002160152002 CR4: 00000000007706e0 [ 479.826597] Call Trace: [ 479.826598] <IRQ> [ 479.826603] smb3_cleanup_fs_context_contents.part.0+0x19/0xc0 [cifs] [ 479.826660] smb3_cleanup_fs_context+0x18/0x30 [cifs] [ 479.826694] delayed_free+0x1f/0x30 [cifs] [ 479.826720] rcu_core+0x32a/0x500 [ 479.826725] rcu_core_si+0xe/0x10 [ 479.826727] __do_softirq+0xe0/0x29b [ 479.826731] asm_call_irq_on_stack+0xf/0x20 [ 479.826734] </IRQ> [ 479.826735] do_softirq_own_stack+0x3d/0x50 [ 479.826739] irq_exit_rcu+0xa4/0xb0 [ 479.826743] sysvec_apic_timer_interrupt+0x3d/0x90 [ 479.826748] ? asm_sysvec_apic_timer_interrupt+0xa/0x20 [ 479.826750] asm_sysvec_apic_timer_interrupt+0x12/0x20 [ 479.826753] RIP: 0033:0x7f410e544e98 [Fix] The issue happens because we fall through a goto label, and free the same cifs_sb->ctx pointer twice. The first happens when we fall through out_super to out: 790 struct dentry * - 791 cifs_smb3_do_mount(struct file_system_type *fs_type, - 792 int flags, struct smb3_fs_context *old_ctx) - 793 { + 791 cifs_smb3_do_mount(struct file_system_type *fs_type, + 792 int flags, struct smb3_fs_context *old_ctx) + 793 { ... - 883 out_super: - 884 deactivate_locked_super(sb); - 885 out: - 886 if (cifs_sb) { - 887 kfree(cifs_sb->prepath); - 888 smb3_cleanup_fs_context(cifs_sb->ctx); - 889 kfree(cifs_sb); - 890 } - 891 return root; - 892 } - - The second happens in deactivate_locked_super() when we eventually make way to delayed_free() after many function calls inbetween: + 883 out_super: + 884 deactivate_locked_super(sb); + 885 out: + 886 if (cifs_sb) { + 887 kfree(cifs_sb->prepath); + 888 smb3_cleanup_fs_context(cifs_sb->ctx); + 889 kfree(cifs_sb); + 890 } + 891 return root; + 892 } + + The second happens in deactivate_locked_super() when we eventually make + way to delayed_free() after many function calls inbetween: 3779 static void delayed_free(struct rcu_head *p) 3780 { 3781 struct cifs_sb_info *cifs_sb = container_of(p, struct cifs_sb_info, rcu); 3782 3783 unload_nls(cifs_sb->local_nls); 3784 smb3_cleanup_fs_context(cifs_sb->ctx); 3785 kfree(cifs_sb); 3786 } smb3_cleanup_fs_context() frees cifs_sb->ctx, as well as all of its pointers in the struct. I came across the following mailing list discussion about a double free occurring during cifs_smb3_do_mount() when we fail to get a reference to a root dentry [2][3]. [2] https://www.spinics.net/lists/linux-cifs/msg24485.html [3] https://www.spinics.net/lists/linux-cifs/msg24486.html For the mailing list discussion, there is a patch submitted [4], and it was merged into mainline in 5.17-rc5 in the below commit: [4] https://www.spinics.net/lists/linux-cifs/msg24487.html commit 3d6cc9898efdfb062efb74dc18cfc700e082f5d5 Author: Ronnie Sahlberg <lsahl...@redhat.com> Date: Fri Feb 11 02:59:15 2022 +1000 Subject: cifs: fix double free race when mount fails in cifs_get_root() Link: https://github.com/torvalds/linux/commit/3d6cc9898efdfb062efb74dc18cfc700e082f5d5 This was fixed-released in 5.13.0-48-generic and 5.15.0-23-generic. [Testcase] Attempt to mount a cifs share where it would fail during the initial mount, e.g. attempting to mount a cifs share with kerberos authentication, with an out of date or invalid kerberos ticket. [Where problems could occur] The fix adds a return to the out_super label, to prevent fallthrough to out. All resources will still be cleaned up correctly through the call to deactivate_locked_super(), which will eventually reach delayed_free() and free the resources there, so there won't be any memory leaks of any sort that arise due to the patch. If a regression were to occur, it would affect users of cifs mounts, that error out and fail during the initial mounting stage. A workaround would be to correct the issue that prevents mount in the first place, so it would avoid the teardown code on mount failure. ** Tags added: sts -- You received this bug notification because you are a member of Kernel Packages, which is subscribed to linux in Ubuntu. https://bugs.launchpad.net/bugs/1978423 Title: cifs: Double free in cifs_smb3_do_mount() when mount fails in cifs_get_root() Status in linux package in Ubuntu: Fix Released Status in linux source package in Impish: Fix Released Status in linux source package in Jammy: Fix Released Bug description: BugLink: https://bugs.launchpad.net/bugs/1978423 [Impact] When attempting to mount a cifs share, and it fails while the kernel is attempting to get the root inode, typically in cifs_get_root(), a double free can occur leading to a general protection fault which panics the system. For example, if we try to mount a cifs share with an out of date kerberos ticket: [ 479.783182] CIFS: Attempting to mount \\cifs-host\cifs-share [ 479.791769] CIFS: VFS: Verify user has a krb5 ticket and keyutils is installed [ 479.791774] CIFS: VFS: \\cifs-host Send error in SessSetup = -126 [ 479.791777] CIFS: VFS: cifs_read_super: get root inode failed We hit a general protection fault: [ 479.826541] general protection fault, probably for non-canonical address 0x2a8e69ddd8028c0: 0000 [#1] SMP NOPTI [ 479.826546] CPU: 9 PID: 8826 Comm: nautilus Kdump: loaded Tainted: P OE 5.11.0-40-generic #44~20.04.2-Ubuntu [ 479.826549] Hardware name: VMware, Inc. VMware7,1/440BX Desktop Reference Platform, BIOS VMW71.00V.18227214.B64.2106252220 06/25/2021 [ 479.826551] RIP: 0010:kfree+0x5d/0x420 [ 479.826574] CR2: 0000559ba2c12000 CR3: 0000002160152002 CR4: 00000000007706e0 [ 479.826597] Call Trace: [ 479.826598] <IRQ> [ 479.826603] smb3_cleanup_fs_context_contents.part.0+0x19/0xc0 [cifs] [ 479.826660] smb3_cleanup_fs_context+0x18/0x30 [cifs] [ 479.826694] delayed_free+0x1f/0x30 [cifs] [ 479.826720] rcu_core+0x32a/0x500 [ 479.826725] rcu_core_si+0xe/0x10 [ 479.826727] __do_softirq+0xe0/0x29b [ 479.826731] asm_call_irq_on_stack+0xf/0x20 [ 479.826734] </IRQ> [ 479.826735] do_softirq_own_stack+0x3d/0x50 [ 479.826739] irq_exit_rcu+0xa4/0xb0 [ 479.826743] sysvec_apic_timer_interrupt+0x3d/0x90 [ 479.826748] ? asm_sysvec_apic_timer_interrupt+0xa/0x20 [ 479.826750] asm_sysvec_apic_timer_interrupt+0x12/0x20 [ 479.826753] RIP: 0033:0x7f410e544e98 [Fix] The issue happens because we fall through a goto label, and free the same cifs_sb->ctx pointer twice. The first happens when we fall through out_super to out: 790 struct dentry * 791 cifs_smb3_do_mount(struct file_system_type *fs_type, 792 int flags, struct smb3_fs_context *old_ctx) 793 { ... 883 out_super: 884 deactivate_locked_super(sb); 885 out: 886 if (cifs_sb) { 887 kfree(cifs_sb->prepath); 888 smb3_cleanup_fs_context(cifs_sb->ctx); 889 kfree(cifs_sb); 890 } 891 return root; 892 } The second happens in deactivate_locked_super() when we eventually make way to delayed_free() after many function calls inbetween: 3779 static void delayed_free(struct rcu_head *p) 3780 { 3781 struct cifs_sb_info *cifs_sb = container_of(p, struct cifs_sb_info, rcu); 3782 3783 unload_nls(cifs_sb->local_nls); 3784 smb3_cleanup_fs_context(cifs_sb->ctx); 3785 kfree(cifs_sb); 3786 } smb3_cleanup_fs_context() frees cifs_sb->ctx, as well as all of its pointers in the struct. I came across the following mailing list discussion about a double free occurring during cifs_smb3_do_mount() when we fail to get a reference to a root dentry [2][3]. [2] https://www.spinics.net/lists/linux-cifs/msg24485.html [3] https://www.spinics.net/lists/linux-cifs/msg24486.html For the mailing list discussion, there is a patch submitted [4], and it was merged into mainline in 5.17-rc5 in the below commit: [4] https://www.spinics.net/lists/linux-cifs/msg24487.html commit 3d6cc9898efdfb062efb74dc18cfc700e082f5d5 Author: Ronnie Sahlberg <lsahl...@redhat.com> Date: Fri Feb 11 02:59:15 2022 +1000 Subject: cifs: fix double free race when mount fails in cifs_get_root() Link: https://github.com/torvalds/linux/commit/3d6cc9898efdfb062efb74dc18cfc700e082f5d5 This was fixed-released in 5.13.0-48-generic and 5.15.0-23-generic. [Testcase] Attempt to mount a cifs share where it would fail during the initial mount, e.g. attempting to mount a cifs share with kerberos authentication, with an out of date or invalid kerberos ticket. [Where problems could occur] The fix adds a return to the out_super label, to prevent fallthrough to out. All resources will still be cleaned up correctly through the call to deactivate_locked_super(), which will eventually reach delayed_free() and free the resources there, so there won't be any memory leaks of any sort that arise due to the patch. If a regression were to occur, it would affect users of cifs mounts, that error out and fail during the initial mounting stage. A workaround would be to correct the issue that prevents mount in the first place, so it would avoid the teardown code on mount failure. To manage notifications about this bug go to: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1978423/+subscriptions -- Mailing list: https://launchpad.net/~kernel-packages Post to : kernel-packages@lists.launchpad.net Unsubscribe : https://launchpad.net/~kernel-packages More help : https://help.launchpad.net/ListHelp