From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-pl1-f172.google.com (mail-pl1-f172.google.com [209.85.214.172]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BEF9F243376 for ; Thu, 16 Apr 2026 02:28:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.172 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776306501; cv=none; b=RIZaYZnuaURxFSj7easrdA9+eo5DokgOAZvZBKRBPi+ZpQaJBGm0zhMg0SBWrHizJB6DAuHP05yt5FDt5/tsNEKXCTiRljBYPCfcbeI5k+6o9MjbrOOSouOF8FkArSQ7N5qhi3KWyaIgU6VtKKQ9y0BF3q7Vft7H7IP12QoiqAo= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776306501; c=relaxed/simple; bh=KKIpoYq2uErfaHaKJ+Vur6Kcodxd4Fi9QHqXgTG5Zvg=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version:Content-Type; b=h4Lmx/y/Nm6UNxePXImnoVBK6TPxCqOQHduMQmSw1CK7iBa/IEuw7ZqLeOjd24LvPFiXyQxfaFGjYUOtFgGZTg8PxekIqrDb8aHmPvTkv08gwNPQMz0b6LG0EtlIsHWMtbY5/3s6TdRS0/To2Jd6APG0GlMPSw+fqQr5q42tubE= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=qTRvua96; arc=none smtp.client-ip=209.85.214.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="qTRvua96" Received: by mail-pl1-f172.google.com with SMTP id d9443c01a7336-2a8720818aeso8657445ad.1 for ; Wed, 15 Apr 2026 19:28:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1776306499; x=1776911299; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=mJGzIbGnleMhmFoh5QkhawpHd8PMOA09v6aeOmjNus8=; b=qTRvua96RpnB2CUnJUlFltedgHQ0yaX4rcD72uyFFrNJXEvYhjAbBz2LonBqr6CWds 47r3j/lwH4nkTSOyOrItogftCKsT392eqHsWXCrGqZfX4JCS464TvzGO/MPaw4+558fw 7dWiH4BLP+evx6UzJWttIl/t8p0lTUJCWz0pbv+coIOn5cag+UHvs0jDv8VelE/STURb ZHgqD2WzhTbZc7eHO9P9/2DXvXLFTtLQmpXFc8lOdozujkjMW/nAW/ejWPZYBCnF0ViL d+KwxPjIkiIG/RcolSStBCku3ZtW1kgcFdFco3Z/uZpM/AgxLuUv497BLpxEhit2+lGs SUYw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1776306499; x=1776911299; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=mJGzIbGnleMhmFoh5QkhawpHd8PMOA09v6aeOmjNus8=; b=LgrqEbYpjAoy0H6OurDPaiwDygCqvS7Jjos+87Q8+AGS+Zk+sF/aK5PFkneGIIPnAC +odn+el9wvtYkI0M842SyH9sGlKBhrnj1/2qVLuc0/D6jHcVP17V2fxshiz8PO2G+XIQ EAgn9QcYjpcVPz7OrV4sICsEIxXmKLwH7yXHhAYY5EfPFjy43+shIHSfWhPRlO5mS4ge OvYBcZjQVyM/9a9wX6Gu9VACJexhWIe7HH/snHALdMbkj76fpsiwyY2j1JlhMIzQQ+RJ KGEQeUC1Yx7iG5zj5oxZ036p7Cs/ozpyypN6jDyQ9O4YBtGXaYstpq54/pPWYEaC5uD4 +iLw== X-Forwarded-Encrypted: i=1; AFNElJ8i01lRmWtVuwvob3RFWpWmZRC6zYxrmEo6RHM0apuYbh3gPD5oUiM9htB74eJGzFA1kokVYIWfUBI8gkE=@vger.kernel.org X-Gm-Message-State: AOJu0Yy8CtGOhzZ/hF/DXHRhCROkNhJDqG+jPGcxRiGJwnNm9wx8kDcM scdMj3GILLiS0IG4xzH7mwIkn0pkbrkom76uA6VYzA27TLdV9BsdZ1fMXp6B9Ts6 X-Gm-Gg: AeBDieslFR4lIdAJvtZdNdW42hwLRdfetabYdN+JUw9S8Uq1Y+ceZKDpXgln2bSBdLC 5+h05VjyCQqC0/CffsSuJiithlsWovR/iSzOyOzDnzwEz1o2A+lA2eXewrL0PnSDQcM5DHZg7cE knFDTXFz0uEgbNfFVU8pN/JcZQK4+Qlhhzyi9DeIgo42x+77UeHTetjmcm/71b0JfQzRdQGRW4k Hpr+fEYOqwtGyx/Ne0VWP5BGczRFYmZF33+2x9g1SgP4A3hsMZM4/58kpeL9iwXfT7tbBXS4A00 1M3GonxmZNe42l2pfXQd0cuyksLvhVJ7OX/EraWHC2CXAh3HKeD0TmajJWt6qBpNZCypgFgjGiV 9beNoQMUJVyvRELTqJfnDpIvlxSAbvJeV7a198NkhqTo0HNgl/XhzJH2bjTIwqTqUejGrIXjqqL h1TZoO6iM2km4DVJRb X-Received: by 2002:a17:903:2292:b0:2b2:4f56:d571 with SMTP id d9443c01a7336-2b5eda2f0c6mr4588475ad.4.1776306499043; Wed, 15 Apr 2026 19:28:19 -0700 (PDT) Received: from ser8.. ([221.156.231.192]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2b4782cb32csm38417295ad.79.2026.04.15.19.28.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 15 Apr 2026 19:28:18 -0700 (PDT) From: DaeMyung Kang To: sfrench@samba.org Cc: pc@manguebit.org, ronniesahlberg@gmail.com, sprasad@microsoft.com, tom@talpey.com, bharathsm@microsoft.com, rajasimandal@microsoft.com, linux-cifs@vger.kernel.org, samba-technical@lists.samba.org, linux-kernel@vger.kernel.org, DaeMyung Kang Subject: [PATCH] smb/client: fix chan_max race and rollback in smb3_reconfigure Date: Thu, 16 Apr 2026 11:28:11 +0900 Message-ID: <20260416022811.2692096-1-charsyam@gmail.com> X-Mailer: git-send-email 2.43.0 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit smb3_reconfigure() has two bugs when handling multichannel remount: 1) smb3_sync_ses_chan_max() is called before acquiring CIFS_SES_FLAG_SCALE_CHANNELS. If a concurrent operation (e.g. smb2_reconnect) holds the flag, the current thread takes the loser path and returns -EINVAL, but ses->chan_max has already been updated to the new value. This leaves chan_max inconsistent with the actual channel state. 2) When smb3_update_ses_channels() fails, chan_max is not rolled back to its previous value and the error is not propagated to the caller. The mount command returns success even though the channel configuration was not applied, and repeated failures cause chan_max to drift further from reality. Fix both by moving smb3_sync_ses_chan_max() after the CIFS_SES_FLAG_SCALE_CHANNELS acquisition so the loser path cannot corrupt chan_max, and by restoring chan_max from old_chan_max on update failure while still holding the scaling flag to prevent a concurrent reconfigure from observing the intermediate state. Propagate the error to the caller so userspace is informed. Note: smb3_reconfigure() is not fully transactional — credentials are committed before the multichannel block, so any early return (including the existing CIFS_SES_FLAG_SCALE_CHANNELS loser path) can leave ses->password updated while cifs_sb->ctx is not yet synced. Making the entire function atomic is a larger refactor and is left for a separate patch. Tested with a QEMU VM (ksmbd + cifs) using module-parameter-based fault injection: - Forced smb3_update_ses_channels() failure via module param and verified chan_max is preserved at the old value after remount failure (fault-injection test for rollback). - Pre-set CIFS_SES_FLAG_SCALE_CHANNELS before entering the scaling path and verified the loser path returns -EINVAL without corrupting chan_max (loser-path invariant test). - Repeated 19 forced-failure remounts with varying max_channels (range 2-8) and confirmed no chan_max drift (stress test). All three scenarios pass with the patch and fail without it. Fixes: ef529f655a2c ("cifs: client: allow changing multichannel mount options on remount") Signed-off-by: DaeMyung Kang --- fs/smb/client/fs_context.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/fs/smb/client/fs_context.c b/fs/smb/client/fs_context.c index b9544eb0381b..99e62c2dbf50 100644 --- a/fs/smb/client/fs_context.c +++ b/fs/smb/client/fs_context.c @@ -1085,6 +1085,7 @@ static int smb3_reconfigure(struct fs_context *fc) struct dentry *root = fc->root; struct cifs_sb_info *cifs_sb = CIFS_SB(root->d_sb); struct cifs_ses *ses = cifs_sb_master_tcon(cifs_sb)->ses; + unsigned int old_chan_max; unsigned int rsize = ctx->rsize, wsize = ctx->wsize; char *new_password = NULL, *new_password2 = NULL; bool need_recon = false; @@ -1170,9 +1171,6 @@ static int smb3_reconfigure(struct fs_context *fc) if ((ctx->multichannel != cifs_sb->ctx->multichannel) || (ctx->max_channels != cifs_sb->ctx->max_channels)) { - /* Synchronize ses->chan_max with the new mount context */ - smb3_sync_ses_chan_max(ses, ctx->max_channels); - /* Now update the session's channels to match the new configuration */ /* Prevent concurrent scaling operations */ spin_lock(&ses->ses_lock); if (ses->flags & CIFS_SES_FLAG_SCALE_CHANNELS) { @@ -1183,16 +1181,31 @@ static int smb3_reconfigure(struct fs_context *fc) ses->flags |= CIFS_SES_FLAG_SCALE_CHANNELS; spin_unlock(&ses->ses_lock); + old_chan_max = ses->chan_max; + /* Synchronize ses->chan_max with the new mount context */ + smb3_sync_ses_chan_max(ses, ctx->max_channels); + mutex_unlock(&ses->session_mutex); rc = smb3_update_ses_channels(ses, ses->server, false /* from_reconnect */, false /* disable_mchan */); + /* + * On failure, restore chan_max while still holding + * CIFS_SES_FLAG_SCALE_CHANNELS so a concurrent reconfigure + * cannot observe or race with the rollback. + */ + if (rc < 0) + smb3_sync_ses_chan_max(ses, old_chan_max); + /* Clear scaling flag after operation */ spin_lock(&ses->ses_lock); ses->flags &= ~CIFS_SES_FLAG_SCALE_CHANNELS; spin_unlock(&ses->ses_lock); + + if (rc < 0) + return rc; } else { mutex_unlock(&ses->session_mutex); } -- 2.43.0