From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
To: stable@vger.kernel.org
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
patches@lists.linux.dev, Jan Kara <jack@suse.cz>,
Sasha Levin <sashal@kernel.org>
Subject: [PATCH 6.6 36/67] quota: Detect loops in quota tree
Date: Thu, 15 Aug 2024 15:25:50 +0200 [thread overview]
Message-ID: <20240815131839.707126682@linuxfoundation.org> (raw)
In-Reply-To: <20240815131838.311442229@linuxfoundation.org>
6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jan Kara <jack@suse.cz>
[ Upstream commit a898cb621ac589b0b9e959309689a027e765aa12 ]
Syzbot has found that when it creates corrupted quota files where the
quota tree contains a loop, we will deadlock when tryling to insert a
dquot. Add loop detection into functions traversing the quota tree.
Signed-off-by: Jan Kara <jack@suse.cz>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/quota/quota_tree.c | 128 +++++++++++++++++++++++++++++++-----------
fs/quota/quota_v2.c | 15 +++--
2 files changed, 105 insertions(+), 38 deletions(-)
diff --git a/fs/quota/quota_tree.c b/fs/quota/quota_tree.c
index 0f1493e0f6d05..254f6359b287f 100644
--- a/fs/quota/quota_tree.c
+++ b/fs/quota/quota_tree.c
@@ -21,6 +21,12 @@ MODULE_AUTHOR("Jan Kara");
MODULE_DESCRIPTION("Quota trie support");
MODULE_LICENSE("GPL");
+/*
+ * Maximum quota tree depth we support. Only to limit recursion when working
+ * with the tree.
+ */
+#define MAX_QTREE_DEPTH 6
+
#define __QUOTA_QT_PARANOIA
static int __get_index(struct qtree_mem_dqinfo *info, qid_t id, int depth)
@@ -327,27 +333,36 @@ static uint find_free_dqentry(struct qtree_mem_dqinfo *info,
/* Insert reference to structure into the trie */
static int do_insert_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot,
- uint *treeblk, int depth)
+ uint *blks, int depth)
{
char *buf = kmalloc(info->dqi_usable_bs, GFP_NOFS);
int ret = 0, newson = 0, newact = 0;
__le32 *ref;
uint newblk;
+ int i;
if (!buf)
return -ENOMEM;
- if (!*treeblk) {
+ if (!blks[depth]) {
ret = get_free_dqblk(info);
if (ret < 0)
goto out_buf;
- *treeblk = ret;
+ for (i = 0; i < depth; i++)
+ if (ret == blks[i]) {
+ quota_error(dquot->dq_sb,
+ "Free block already used in tree: block %u",
+ ret);
+ ret = -EIO;
+ goto out_buf;
+ }
+ blks[depth] = ret;
memset(buf, 0, info->dqi_usable_bs);
newact = 1;
} else {
- ret = read_blk(info, *treeblk, buf);
+ ret = read_blk(info, blks[depth], buf);
if (ret < 0) {
quota_error(dquot->dq_sb, "Can't read tree quota "
- "block %u", *treeblk);
+ "block %u", blks[depth]);
goto out_buf;
}
}
@@ -357,8 +372,20 @@ static int do_insert_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot,
info->dqi_blocks - 1);
if (ret)
goto out_buf;
- if (!newblk)
+ if (!newblk) {
newson = 1;
+ } else {
+ for (i = 0; i <= depth; i++)
+ if (newblk == blks[i]) {
+ quota_error(dquot->dq_sb,
+ "Cycle in quota tree detected: block %u index %u",
+ blks[depth],
+ get_index(info, dquot->dq_id, depth));
+ ret = -EIO;
+ goto out_buf;
+ }
+ }
+ blks[depth + 1] = newblk;
if (depth == info->dqi_qtree_depth - 1) {
#ifdef __QUOTA_QT_PARANOIA
if (newblk) {
@@ -370,16 +397,16 @@ static int do_insert_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot,
goto out_buf;
}
#endif
- newblk = find_free_dqentry(info, dquot, &ret);
+ blks[depth + 1] = find_free_dqentry(info, dquot, &ret);
} else {
- ret = do_insert_tree(info, dquot, &newblk, depth+1);
+ ret = do_insert_tree(info, dquot, blks, depth + 1);
}
if (newson && ret >= 0) {
ref[get_index(info, dquot->dq_id, depth)] =
- cpu_to_le32(newblk);
- ret = write_blk(info, *treeblk, buf);
+ cpu_to_le32(blks[depth + 1]);
+ ret = write_blk(info, blks[depth], buf);
} else if (newact && ret < 0) {
- put_free_dqblk(info, buf, *treeblk);
+ put_free_dqblk(info, buf, blks[depth]);
}
out_buf:
kfree(buf);
@@ -390,7 +417,7 @@ static int do_insert_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot,
static inline int dq_insert_tree(struct qtree_mem_dqinfo *info,
struct dquot *dquot)
{
- int tmp = QT_TREEOFF;
+ uint blks[MAX_QTREE_DEPTH] = { QT_TREEOFF };
#ifdef __QUOTA_QT_PARANOIA
if (info->dqi_blocks <= QT_TREEOFF) {
@@ -398,7 +425,11 @@ static inline int dq_insert_tree(struct qtree_mem_dqinfo *info,
return -EIO;
}
#endif
- return do_insert_tree(info, dquot, &tmp, 0);
+ if (info->dqi_qtree_depth >= MAX_QTREE_DEPTH) {
+ quota_error(dquot->dq_sb, "Quota tree depth too big!");
+ return -EIO;
+ }
+ return do_insert_tree(info, dquot, blks, 0);
}
/*
@@ -511,19 +542,20 @@ static int free_dqentry(struct qtree_mem_dqinfo *info, struct dquot *dquot,
/* Remove reference to dquot from tree */
static int remove_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot,
- uint *blk, int depth)
+ uint *blks, int depth)
{
char *buf = kmalloc(info->dqi_usable_bs, GFP_NOFS);
int ret = 0;
uint newblk;
__le32 *ref = (__le32 *)buf;
+ int i;
if (!buf)
return -ENOMEM;
- ret = read_blk(info, *blk, buf);
+ ret = read_blk(info, blks[depth], buf);
if (ret < 0) {
quota_error(dquot->dq_sb, "Can't read quota data block %u",
- *blk);
+ blks[depth]);
goto out_buf;
}
newblk = le32_to_cpu(ref[get_index(info, dquot->dq_id, depth)]);
@@ -532,29 +564,38 @@ static int remove_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot,
if (ret)
goto out_buf;
+ for (i = 0; i <= depth; i++)
+ if (newblk == blks[i]) {
+ quota_error(dquot->dq_sb,
+ "Cycle in quota tree detected: block %u index %u",
+ blks[depth],
+ get_index(info, dquot->dq_id, depth));
+ ret = -EIO;
+ goto out_buf;
+ }
if (depth == info->dqi_qtree_depth - 1) {
ret = free_dqentry(info, dquot, newblk);
- newblk = 0;
+ blks[depth + 1] = 0;
} else {
- ret = remove_tree(info, dquot, &newblk, depth+1);
+ blks[depth + 1] = newblk;
+ ret = remove_tree(info, dquot, blks, depth + 1);
}
- if (ret >= 0 && !newblk) {
- int i;
+ if (ret >= 0 && !blks[depth + 1]) {
ref[get_index(info, dquot->dq_id, depth)] = cpu_to_le32(0);
/* Block got empty? */
for (i = 0; i < (info->dqi_usable_bs >> 2) && !ref[i]; i++)
;
/* Don't put the root block into the free block list */
if (i == (info->dqi_usable_bs >> 2)
- && *blk != QT_TREEOFF) {
- put_free_dqblk(info, buf, *blk);
- *blk = 0;
+ && blks[depth] != QT_TREEOFF) {
+ put_free_dqblk(info, buf, blks[depth]);
+ blks[depth] = 0;
} else {
- ret = write_blk(info, *blk, buf);
+ ret = write_blk(info, blks[depth], buf);
if (ret < 0)
quota_error(dquot->dq_sb,
"Can't write quota tree block %u",
- *blk);
+ blks[depth]);
}
}
out_buf:
@@ -565,11 +606,15 @@ static int remove_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot,
/* Delete dquot from tree */
int qtree_delete_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot)
{
- uint tmp = QT_TREEOFF;
+ uint blks[MAX_QTREE_DEPTH] = { QT_TREEOFF };
if (!dquot->dq_off) /* Even not allocated? */
return 0;
- return remove_tree(info, dquot, &tmp, 0);
+ if (info->dqi_qtree_depth >= MAX_QTREE_DEPTH) {
+ quota_error(dquot->dq_sb, "Quota tree depth too big!");
+ return -EIO;
+ }
+ return remove_tree(info, dquot, blks, 0);
}
EXPORT_SYMBOL(qtree_delete_dquot);
@@ -613,18 +658,20 @@ static loff_t find_block_dqentry(struct qtree_mem_dqinfo *info,
/* Find entry for given id in the tree */
static loff_t find_tree_dqentry(struct qtree_mem_dqinfo *info,
- struct dquot *dquot, uint blk, int depth)
+ struct dquot *dquot, uint *blks, int depth)
{
char *buf = kmalloc(info->dqi_usable_bs, GFP_NOFS);
loff_t ret = 0;
__le32 *ref = (__le32 *)buf;
+ uint blk;
+ int i;
if (!buf)
return -ENOMEM;
- ret = read_blk(info, blk, buf);
+ ret = read_blk(info, blks[depth], buf);
if (ret < 0) {
quota_error(dquot->dq_sb, "Can't read quota tree block %u",
- blk);
+ blks[depth]);
goto out_buf;
}
ret = 0;
@@ -636,8 +683,19 @@ static loff_t find_tree_dqentry(struct qtree_mem_dqinfo *info,
if (ret)
goto out_buf;
+ /* Check for cycles in the tree */
+ for (i = 0; i <= depth; i++)
+ if (blk == blks[i]) {
+ quota_error(dquot->dq_sb,
+ "Cycle in quota tree detected: block %u index %u",
+ blks[depth],
+ get_index(info, dquot->dq_id, depth));
+ ret = -EIO;
+ goto out_buf;
+ }
+ blks[depth + 1] = blk;
if (depth < info->dqi_qtree_depth - 1)
- ret = find_tree_dqentry(info, dquot, blk, depth+1);
+ ret = find_tree_dqentry(info, dquot, blks, depth + 1);
else
ret = find_block_dqentry(info, dquot, blk);
out_buf:
@@ -649,7 +707,13 @@ static loff_t find_tree_dqentry(struct qtree_mem_dqinfo *info,
static inline loff_t find_dqentry(struct qtree_mem_dqinfo *info,
struct dquot *dquot)
{
- return find_tree_dqentry(info, dquot, QT_TREEOFF, 0);
+ uint blks[MAX_QTREE_DEPTH] = { QT_TREEOFF };
+
+ if (info->dqi_qtree_depth >= MAX_QTREE_DEPTH) {
+ quota_error(dquot->dq_sb, "Quota tree depth too big!");
+ return -EIO;
+ }
+ return find_tree_dqentry(info, dquot, blks, 0);
}
int qtree_read_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot)
diff --git a/fs/quota/quota_v2.c b/fs/quota/quota_v2.c
index ae99e7b88205b..7978ab671e0c6 100644
--- a/fs/quota/quota_v2.c
+++ b/fs/quota/quota_v2.c
@@ -166,14 +166,17 @@ static int v2_read_file_info(struct super_block *sb, int type)
i_size_read(sb_dqopt(sb)->files[type]));
goto out_free;
}
- if (qinfo->dqi_free_blk >= qinfo->dqi_blocks) {
- quota_error(sb, "Free block number too big (%u >= %u).",
- qinfo->dqi_free_blk, qinfo->dqi_blocks);
+ if (qinfo->dqi_free_blk && (qinfo->dqi_free_blk <= QT_TREEOFF ||
+ qinfo->dqi_free_blk >= qinfo->dqi_blocks)) {
+ quota_error(sb, "Free block number %u out of range (%u, %u).",
+ qinfo->dqi_free_blk, QT_TREEOFF, qinfo->dqi_blocks);
goto out_free;
}
- if (qinfo->dqi_free_entry >= qinfo->dqi_blocks) {
- quota_error(sb, "Block with free entry too big (%u >= %u).",
- qinfo->dqi_free_entry, qinfo->dqi_blocks);
+ if (qinfo->dqi_free_entry && (qinfo->dqi_free_entry <= QT_TREEOFF ||
+ qinfo->dqi_free_entry >= qinfo->dqi_blocks)) {
+ quota_error(sb, "Block with free entry %u out of range (%u, %u).",
+ qinfo->dqi_free_entry, QT_TREEOFF,
+ qinfo->dqi_blocks);
goto out_free;
}
ret = 0;
--
2.43.0
next prev parent reply other threads:[~2024-08-15 14:08 UTC|newest]
Thread overview: 79+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-08-15 13:25 [PATCH 6.6 00/67] 6.6.47-rc1 review Greg Kroah-Hartman
2024-08-15 13:25 ` [PATCH 6.6 01/67] exec: Fix ToCToU between perm check and set-uid/gid usage Greg Kroah-Hartman
2024-08-15 13:25 ` [PATCH 6.6 02/67] ASoC: topology: Clean up route loading Greg Kroah-Hartman
2024-08-15 13:25 ` [PATCH 6.6 03/67] ASoC: topology: Fix route memory corruption Greg Kroah-Hartman
2024-08-15 13:25 ` [PATCH 6.6 04/67] LoongArch: Define __ARCH_WANT_NEW_STAT in unistd.h Greg Kroah-Hartman
2024-08-15 13:25 ` [PATCH 6.6 05/67] NFSD: Rewrite synopsis of nfsd_percpu_counters_init() Greg Kroah-Hartman
2024-08-15 13:25 ` [PATCH 6.6 06/67] NFSD: Fix frame size warning in svc_export_parse() Greg Kroah-Hartman
2024-08-15 13:25 ` [PATCH 6.6 07/67] sunrpc: dont change ->sv_stats if it doesnt exist Greg Kroah-Hartman
2024-08-15 13:25 ` [PATCH 6.6 08/67] nfsd: stop setting ->pg_stats for unused stats Greg Kroah-Hartman
2024-08-15 13:25 ` [PATCH 6.6 09/67] sunrpc: pass in the sv_stats struct through svc_create_pooled Greg Kroah-Hartman
2024-08-15 13:25 ` [PATCH 6.6 10/67] sunrpc: remove ->pg_stats from svc_program Greg Kroah-Hartman
2024-08-15 13:25 ` [PATCH 6.6 11/67] sunrpc: use the struct net as the svc proc private Greg Kroah-Hartman
2024-08-15 13:25 ` [PATCH 6.6 12/67] nfsd: rename NFSD_NET_* to NFSD_STATS_* Greg Kroah-Hartman
2024-08-15 13:25 ` [PATCH 6.6 13/67] nfsd: expose /proc/net/sunrpc/nfsd in net namespaces Greg Kroah-Hartman
2024-08-15 13:25 ` [PATCH 6.6 14/67] nfsd: make all of the nfsd stats per-network namespace Greg Kroah-Hartman
2024-08-15 13:25 ` [PATCH 6.6 15/67] nfsd: remove nfsd_stats, make th_cnt a global counter Greg Kroah-Hartman
2024-08-15 13:25 ` [PATCH 6.6 16/67] nfsd: make svc_stat per-network namespace instead of global Greg Kroah-Hartman
2024-08-15 13:25 ` [PATCH 6.6 17/67] mm: gup: stop abusing try_grab_folio Greg Kroah-Hartman
2024-08-15 13:25 ` [PATCH 6.6 18/67] nvme/pci: Add APST quirk for Lenovo N60z laptop Greg Kroah-Hartman
2024-08-15 13:25 ` [PATCH 6.6 19/67] genirq/cpuhotplug: Skip suspended interrupts when restoring affinity Greg Kroah-Hartman
2024-08-15 13:25 ` [PATCH 6.6 20/67] genirq/cpuhotplug: Retry with cpu_online_mask when migration fails Greg Kroah-Hartman
2024-08-15 13:25 ` [PATCH 6.6 21/67] cgroup: Make operations on the cgroup root_list RCU safe Greg Kroah-Hartman
2024-08-15 13:25 ` [PATCH 6.6 22/67] tcp_metrics: optimize tcp_metrics_flush_all() Greg Kroah-Hartman
2024-08-15 13:25 ` [PATCH 6.6 23/67] wifi: mac80211: take wiphy lock for MAC addr change Greg Kroah-Hartman
2024-08-15 13:25 ` [PATCH 6.6 24/67] wifi: mac80211: fix change_address deadlock during unregister Greg Kroah-Hartman
2024-08-15 13:25 ` [PATCH 6.6 25/67] fs: Convert to bdev_open_by_dev() Greg Kroah-Hartman
2024-08-15 13:25 ` [PATCH 6.6 26/67] jfs: " Greg Kroah-Hartman
2024-08-15 13:25 ` [PATCH 6.6 27/67] jfs: fix log->bdev_handle null ptr deref in lbmStartIO Greg Kroah-Hartman
2024-08-15 13:25 ` [PATCH 6.6 28/67] net: dont dump stack on queue timeout Greg Kroah-Hartman
2024-08-15 13:25 ` [PATCH 6.6 29/67] jfs: fix shift-out-of-bounds in dbJoin Greg Kroah-Hartman
2024-08-15 14:13 ` Dave Kleikamp
2024-08-15 14:19 ` Greg Kroah-Hartman
2024-08-15 16:24 ` Dave Kleikamp
2024-08-15 13:25 ` [PATCH 6.6 30/67] squashfs: squashfs_read_data need to check if the length is 0 Greg Kroah-Hartman
2024-08-15 13:25 ` [PATCH 6.6 31/67] Squashfs: fix variable overflow triggered by sysbot Greg Kroah-Hartman
2024-08-15 13:25 ` [PATCH 6.6 32/67] reiserfs: fix uninit-value in comp_keys Greg Kroah-Hartman
2024-08-15 13:25 ` [PATCH 6.6 33/67] erofs: avoid debugging output for (de)compressed data Greg Kroah-Hartman
2024-08-15 13:25 ` [PATCH 6.6 34/67] net: tls, add test to capture error on large splice Greg Kroah-Hartman
2024-08-15 13:25 ` [PATCH 6.6 35/67] Input: bcm5974 - check endpoint type before starting traffic Greg Kroah-Hartman
2024-08-15 13:25 ` Greg Kroah-Hartman [this message]
2024-08-15 13:25 ` [PATCH 6.6 37/67] net:rds: Fix possible deadlock in rds_message_put Greg Kroah-Hartman
2024-08-15 13:25 ` [PATCH 6.6 38/67] net: sctp: fix skb leak in sctp_inq_free() Greg Kroah-Hartman
2024-08-15 13:25 ` [PATCH 6.6 39/67] pppoe: Fix memory leak in pppoe_sendmsg() Greg Kroah-Hartman
2024-08-15 13:25 ` [PATCH 6.6 40/67] bpf: Replace bpf_lpm_trie_key 0-length array with flexible array Greg Kroah-Hartman
2024-08-15 13:25 ` [PATCH 6.6 41/67] bpf: Avoid kfree_rcu() under lock in bpf_lpm_trie Greg Kroah-Hartman
2024-08-15 13:25 ` [PATCH 6.6 42/67] fs: Annotate struct file_handle with __counted_by() and use struct_size() Greg Kroah-Hartman
2024-08-15 13:25 ` [PATCH 6.6 43/67] mISDN: fix MISDN_TIME_STAMP handling Greg Kroah-Hartman
2024-08-15 13:25 ` [PATCH 6.6 44/67] net: add copy_safe_from_sockptr() helper Greg Kroah-Hartman
2024-08-15 13:25 ` [PATCH 6.6 45/67] nfc: llcp: fix nfc_llcp_setsockopt() unsafe copies Greg Kroah-Hartman
2024-08-15 13:26 ` [PATCH 6.6 46/67] Bluetooth: RFCOMM: Fix not validating setsockopt user input Greg Kroah-Hartman
2024-08-15 13:26 ` [PATCH 6.6 47/67] ext4: fold quota accounting into ext4_xattr_inode_lookup_create() Greg Kroah-Hartman
2024-08-15 13:26 ` [PATCH 6.6 48/67] ext4: do not create EA inode under buffer lock Greg Kroah-Hartman
2024-08-15 13:26 ` [PATCH 6.6 49/67] mm/page_table_check: support userfault wr-protect entries Greg Kroah-Hartman
2024-08-15 13:26 ` [PATCH 6.6 50/67] wifi: cfg80211: restrict NL80211_ATTR_TXQ_QUANTUM values Greg Kroah-Hartman
2024-08-15 13:26 ` [PATCH 6.6 51/67] ext4: convert ext4_da_do_write_end() to take a folio Greg Kroah-Hartman
2024-08-15 13:26 ` [PATCH 6.6 52/67] ext4: sanity check for NULL pointer after ext4_force_shutdown Greg Kroah-Hartman
2024-08-15 13:26 ` [PATCH 6.6 53/67] bpf, net: Use DEV_STAT_INC() Greg Kroah-Hartman
2024-08-15 13:26 ` [PATCH 6.6 54/67] f2fs: fix to do sanity check on F2FS_INLINE_DATA flag in inode during GC Greg Kroah-Hartman
2024-08-15 13:26 ` [PATCH 6.6 55/67] f2fs: fix to cover read extent cache access with lock Greg Kroah-Hartman
2024-08-15 13:26 ` [PATCH 6.6 56/67] fou: remove warn in gue_gro_receive on unsupported protocol Greg Kroah-Hartman
2024-08-15 13:26 ` [PATCH 6.6 57/67] jfs: fix null ptr deref in dtInsertEntry Greg Kroah-Hartman
2024-08-15 13:26 ` [PATCH 6.6 58/67] jfs: Fix shift-out-of-bounds in dbDiscardAG Greg Kroah-Hartman
2024-08-15 13:26 ` [PATCH 6.6 59/67] fs/ntfs3: Do copy_to_user out of run_lock Greg Kroah-Hartman
2024-08-15 13:26 ` [PATCH 6.6 60/67] ALSA: usb: Fix UBSAN warning in parse_audio_unit() Greg Kroah-Hartman
2024-08-15 13:26 ` [PATCH 6.6 61/67] binfmt_flat: Fix corruption when not offsetting data start Greg Kroah-Hartman
2024-08-15 13:26 ` [PATCH 6.6 62/67] Revert "jfs: fix shift-out-of-bounds in dbJoin" Greg Kroah-Hartman
2024-08-15 13:26 ` [PATCH 6.6 63/67] Revert "Input: bcm5974 - check endpoint type before starting traffic" Greg Kroah-Hartman
2024-08-15 13:26 ` [PATCH 6.6 64/67] mm/debug_vm_pgtable: drop RANDOM_ORVALUE trick Greg Kroah-Hartman
2024-08-15 13:26 ` [PATCH 6.6 65/67] cgroup: Move rcu_head up near the top of cgroup_root Greg Kroah-Hartman
2024-08-15 13:26 ` [PATCH 6.6 66/67] KVM: arm64: Dont defer TLB invalidation when zapping table entries Greg Kroah-Hartman
2024-08-15 13:26 ` [PATCH 6.6 67/67] KVM: arm64: Dont pass a TLBI level hint " Greg Kroah-Hartman
2024-08-15 19:35 ` [PATCH 6.6 00/67] 6.6.47-rc1 review ChromeOS Kernel Stable Merge
2024-08-15 19:46 ` Peter Schneider
2024-08-15 21:59 ` Florian Fainelli
2024-08-16 8:47 ` Anders Roxell
2024-08-16 11:24 ` Mark Brown
2024-08-16 11:56 ` Takeshi Ogasawara
2024-08-16 19:47 ` Jon Hunter
2024-08-16 20:40 ` Ron Economos
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20240815131839.707126682@linuxfoundation.org \
--to=gregkh@linuxfoundation.org \
--cc=jack@suse.cz \
--cc=patches@lists.linux.dev \
--cc=sashal@kernel.org \
--cc=stable@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox