Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile.rhelver
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ RHEL_MINOR = 10
#
# Use this spot to avoid future merge conflicts.
# Do not trim this comment.
RHEL_RELEASE = 553.77.1
RHEL_RELEASE = 553.79.1

#
# ZSTREAM
Expand Down
2 changes: 0 additions & 2 deletions arch/x86/kvm/svm/svm.c
Original file line number Diff line number Diff line change
Expand Up @@ -3431,8 +3431,6 @@ static void svm_inject_irq(struct kvm_vcpu *vcpu)
{
struct vcpu_svm *svm = to_svm(vcpu);

BUG_ON(!(gif_set(svm)));

trace_kvm_inj_virq(vcpu->arch.interrupt.nr);
++vcpu->stat.irq_injections;

Expand Down
158 changes: 158 additions & 0 deletions ciq/ciq_backports/kernel-4.18.0-553.78.1.el8_10/705c7910.failed
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
smb: client: fix use-after-free in cifs_oplock_break

jira LE-4375
cve CVE-2025-38527
Rebuild_History Non-Buildable kernel-4.18.0-553.78.1.el8_10
commit-author Wang Zhaolong <wangzhaolong@huaweicloud.com>
commit 705c79101ccf9edea5a00d761491a03ced314210
Empty-Commit: Cherry-Pick Conflicts during history rebuild.
Will be included in final tarball splat. Ref for failed cherry-pick at:
ciq/ciq_backports/kernel-4.18.0-553.78.1.el8_10/705c7910.failed

A race condition can occur in cifs_oplock_break() leading to a
use-after-free of the cinode structure when unmounting:

cifs_oplock_break()
_cifsFileInfo_put(cfile)
cifsFileInfo_put_final()
cifs_sb_deactive()
[last ref, start releasing sb]
kill_sb()
kill_anon_super()
generic_shutdown_super()
evict_inodes()
dispose_list()
evict()
destroy_inode()
call_rcu(&inode->i_rcu, i_callback)
spin_lock(&cinode->open_file_lock) <- OK
[later] i_callback()
cifs_free_inode()
kmem_cache_free(cinode)
spin_unlock(&cinode->open_file_lock) <- UAF
cifs_done_oplock_break(cinode) <- UAF

The issue occurs when umount has already released its reference to the
superblock. When _cifsFileInfo_put() calls cifs_sb_deactive(), this
releases the last reference, triggering the immediate cleanup of all
inodes under RCU. However, cifs_oplock_break() continues to access the
cinode after this point, resulting in use-after-free.

Fix this by holding an extra reference to the superblock during the
entire oplock break operation. This ensures that the superblock and
its inodes remain valid until the oplock break completes.

Link: https://bugzilla.kernel.org/show_bug.cgi?id=220309
Fixes: b98749cac4a6 ("CIFS: keep FileInfo handle live during oplock break")
Reviewed-by: Paulo Alcantara (Red Hat) <pc@manguebit.org>
Signed-off-by: Wang Zhaolong <wangzhaolong@huaweicloud.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
(cherry picked from commit 705c79101ccf9edea5a00d761491a03ced314210)
Signed-off-by: Jonathan Maple <jmaple@ciq.com>

# Conflicts:
# fs/cifs/file.c
diff --cc fs/cifs/file.c
index 6aaac9bc59dc,1421bde045c2..000000000000
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@@ -4767,12 -3088,23 +4767,23 @@@ void cifs_oplock_break(struct work_stru
struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo,
oplock_break);
struct inode *inode = d_inode(cfile->dentry);
++<<<<<<< HEAD:fs/cifs/file.c
++=======
+ struct super_block *sb = inode->i_sb;
+ struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
++>>>>>>> 705c79101ccf (smb: client: fix use-after-free in cifs_oplock_break):fs/smb/client/file.c
struct cifsInodeInfo *cinode = CIFS_I(inode);
- struct cifs_tcon *tcon;
- struct TCP_Server_Info *server;
- struct tcon_link *tlink;
+ struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
+ struct TCP_Server_Info *server = tcon->ses->server;
int rc = 0;
- bool purge_cache = false, oplock_break_cancelled;
- __u64 persistent_fid, volatile_fid;
- __u16 net_fid;
+ bool purge_cache = false;

+ /*
+ * Hold a reference to the superblock to prevent it and its inodes from
+ * being freed while we are accessing cinode. Otherwise, _cifsFileInfo_put()
+ * may release the last reference to the sb and trigger inode eviction.
+ */
+ cifs_sb_active(sb);
wait_on_bit(&cinode->flags, CIFS_INODE_PENDING_WRITERS,
TASK_UNINTERRUPTIBLE);

@@@ -4808,39 -3146,40 +4819,40 @@@

oplock_break_ack:
/*
- * When oplock break is received and there are no active
- * file handles but cached, then schedule deferred close immediately.
- * So, new open will not use cached handle.
- */
-
- if (!CIFS_CACHE_HANDLE(cinode) && !list_empty(&cinode->deferred_closes))
- cifs_close_deferred_file(cinode);
-
- persistent_fid = cfile->fid.persistent_fid;
- volatile_fid = cfile->fid.volatile_fid;
- net_fid = cfile->fid.netfid;
- oplock_break_cancelled = cfile->oplock_break_cancelled;
-
- _cifsFileInfo_put(cfile, false /* do not wait for ourself */, false);
- /*
- * MS-SMB2 3.2.5.19.1 and 3.2.5.19.2 (and MS-CIFS 3.2.5.42) do not require
- * an acknowledgment to be sent when the file has already been closed.
+ * releasing stale oplock after recent reconnect of smb session using
+ * a now incorrect file handle is not a data integrity issue but do
+ * not bother sending an oplock release if session to server still is
+ * disconnected since oplock already released by the server
*/
- spin_lock(&cinode->open_file_lock);
- /* check list empty since can race with kill_sb calling tree disconnect */
- if (!oplock_break_cancelled && !list_empty(&cinode->openFileList)) {
- spin_unlock(&cinode->open_file_lock);
- rc = server->ops->oplock_response(tcon, persistent_fid,
- volatile_fid, net_fid, cinode);
+ if (!cfile->oplock_break_cancelled) {
+ rc = tcon->ses->server->ops->oplock_response(tcon, &cfile->fid,
+ cinode);
cifs_dbg(FYI, "Oplock release rc = %d\n", rc);
- } else
- spin_unlock(&cinode->open_file_lock);
-
- cifs_put_tlink(tlink);
-out:
+ }
+ _cifsFileInfo_put(cfile, false /* do not wait for ourself */, false);
cifs_done_oplock_break(cinode);
+ cifs_sb_deactive(sb);
}

+/*
+ * The presence of cifs_direct_io() in the address space ops vector
+ * allowes open() O_DIRECT flags which would have failed otherwise.
+ *
+ * In the non-cached mode (mount with cache=none), we shunt off direct read and write requests
+ * so this method should never be called.
+ *
+ * Direct IO is not yet supported in the cached mode.
+ */
+static ssize_t
+cifs_direct_io(struct kiocb *iocb, struct iov_iter *iter)
+{
+ /*
+ * FIXME
+ * Eventually need to support direct IO for non forcedirectio mounts
+ */
+ return -EINVAL;
+}
+
static int cifs_swap_activate(struct swap_info_struct *sis,
struct file *swap_file, sector_t *span)
{
* Unmerged path fs/cifs/file.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
Rebuild_History BUILDABLE
Rebuilding Kernel from rpm changelog with Fuzz Limit: 87.50%
Number of commits in upstream range v4.18~1..kernel-mainline: 567757
Number of commits in rpm: 9
Number of commits matched with upstream: 2 (22.22%)
Number of commits in upstream but not in rpm: 567755
Number of commits NOT found in upstream: 7 (77.78%)

Rebuilding Kernel on Branch rocky8_10_rebuild_kernel-4.18.0-553.78.1.el8_10 for kernel-4.18.0-553.78.1.el8_10
Clean Cherry Picks: 1 (50.00%)
Empty Cherry Picks: 1 (50.00%)
_______________________________

__EMPTY COMMITS__________________________
705c79101ccf9edea5a00d761491a03ced314210 smb: client: fix use-after-free in cifs_oplock_break

__CHANGES NOT IN UPSTREAM________________
Adding prod certs and changed cert date to 20210620
Adding Rocky secure boot certs
Fixing vmlinuz removal
Fixing UEFI CA path
Porting to 8.10, debranding and Rocky branding
Fixing pesign_key_name values
mm/migrate: set swap entry values of THP tail pages properly.
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
Rebuild_History BUILDABLE
Rebuilding Kernel from rpm changelog with Fuzz Limit: 87.50%
Number of commits in upstream range v4.18~1..kernel-mainline: 567757
Number of commits in rpm: 8
Number of commits matched with upstream: 2 (25.00%)
Number of commits in upstream but not in rpm: 567755
Number of commits NOT found in upstream: 6 (75.00%)

Rebuilding Kernel on Branch rocky8_10_rebuild_kernel-4.18.0-553.79.1.el8_10 for kernel-4.18.0-553.79.1.el8_10
Clean Cherry Picks: 2 (100.00%)
Empty Cherry Picks: 0 (0.00%)
_______________________________

__EMPTY COMMITS__________________________

__CHANGES NOT IN UPSTREAM________________
Adding prod certs and changed cert date to 20210620
Adding Rocky secure boot certs
Fixing vmlinuz removal
Fixing UEFI CA path
Porting to 8.10, debranding and Rocky branding
Fixing pesign_key_name values
8 changes: 8 additions & 0 deletions fs/cifs/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -4767,12 +4767,19 @@ void cifs_oplock_break(struct work_struct *work)
struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo,
oplock_break);
struct inode *inode = d_inode(cfile->dentry);
struct super_block *sb = inode->i_sb;
struct cifsInodeInfo *cinode = CIFS_I(inode);
struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
struct TCP_Server_Info *server = tcon->ses->server;
int rc = 0;
bool purge_cache = false;

/*
* Hold a reference to the superblock to prevent it and its inodes from
* being freed while we are accessing cinode. Otherwise, _cifsFileInfo_put()
* may release the last reference to the sb and trigger inode eviction.
*/
cifs_sb_active(sb);
wait_on_bit(&cinode->flags, CIFS_INODE_PENDING_WRITERS,
TASK_UNINTERRUPTIBLE);

Expand Down Expand Up @@ -4820,6 +4827,7 @@ void cifs_oplock_break(struct work_struct *work)
}
_cifsFileInfo_put(cfile, false /* do not wait for ourself */, false);
cifs_done_oplock_break(cinode);
cifs_sb_deactive(sb);
}

/*
Expand Down
11 changes: 9 additions & 2 deletions fs/nfs/export.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,21 @@ nfs_fh_to_dentry(struct super_block *sb, struct fid *fid,
{
struct nfs_fattr *fattr = NULL;
struct nfs_fh *server_fh = nfs_exp_embedfh(fid->raw);
size_t fh_size = offsetof(struct nfs_fh, data) + server_fh->size;
size_t fh_size = offsetof(struct nfs_fh, data);
const struct nfs_rpc_ops *rpc_ops;
struct dentry *dentry;
struct inode *inode;
int len = EMBED_FH_OFF + XDR_QUADLEN(fh_size);
int len = EMBED_FH_OFF;
u32 *p = fid->raw;
int ret;

/* Initial check of bounds */
if (fh_len < len + XDR_QUADLEN(fh_size) ||
fh_len > XDR_QUADLEN(NFS_MAXFHSIZE))
return NULL;
/* Calculate embedded filehandle size */
fh_size += server_fh->size;
len += XDR_QUADLEN(fh_size);
/* NULL translates to ESTALE */
if (fh_len < len || fh_type != len)
return NULL;
Expand Down
6 changes: 5 additions & 1 deletion mm/migrate.c
Original file line number Diff line number Diff line change
Expand Up @@ -441,8 +441,12 @@ int migrate_page_move_mapping(struct address_space *mapping,
if (PageSwapBacked(page)) {
__SetPageSwapBacked(newpage);
if (PageSwapCache(page)) {
int i;

SetPageSwapCache(newpage);
set_page_private(newpage, page_private(page));
for (i = 0; i < (1 << compound_order(page)); i++)
set_page_private(newpage + i,
page_private(page + i));
}
} else {
VM_BUG_ON_PAGE(PageSwapCache(page), page);
Expand Down
5 changes: 5 additions & 0 deletions net/bluetooth/l2cap_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -6339,9 +6339,14 @@ static inline int l2cap_le_command_rej(struct l2cap_conn *conn,
if (!chan)
goto done;

chan = l2cap_chan_hold_unless_zero(chan);
if (!chan)
goto done;

l2cap_chan_lock(chan);
l2cap_chan_del(chan, ECONNREFUSED);
l2cap_chan_unlock(chan);
l2cap_chan_put(chan);

done:
mutex_unlock(&conn->chan_lock);
Expand Down