linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Sasha Levin <sashal@kernel.org>
To: stable@vger.kernel.org, linux-kernel@vger.kernel.org
Cc: Hannes Frederic Sowa <hannes@stressinduktion.org>,
	David Herrmann <dh.herrmann@gmail.com>, Willy Tarreau <w@1wt.eu>,
	Linus Torvalds <torvalds@linux-foundation.org>,
	"David S . Miller" <davem@davemloft.net>,
	Sasha Levin <sashal@kernel.org>
Subject: [PATCH AUTOSEL 3.18 98/98] unix: correctly track in-flight fds in sending process user_struct
Date: Thu, 25 Oct 2018 10:18:53 -0400	[thread overview]
Message-ID: <20181025141853.214051-98-sashal@kernel.org> (raw)
In-Reply-To: <20181025141853.214051-1-sashal@kernel.org>

From: Hannes Frederic Sowa <hannes@stressinduktion.org>

[ Upstream commit 415e3d3e90ce9e18727e8843ae343eda5a58fad6 ]

The commit referenced in the Fixes tag incorrectly accounted the number
of in-flight fds over a unix domain socket to the original opener
of the file-descriptor. This allows another process to arbitrary
deplete the original file-openers resource limit for the maximum of
open files. Instead the sending processes and its struct cred should
be credited.

To do so, we add a reference counted struct user_struct pointer to the
scm_fp_list and use it to account for the number of inflight unix fds.

Fixes: 712f4aad406bb1 ("unix: properly account for FDs passed over unix sockets")
Reported-by: David Herrmann <dh.herrmann@gmail.com>
Cc: David Herrmann <dh.herrmann@gmail.com>
Cc: Willy Tarreau <w@1wt.eu>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Suggested-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
 include/net/af_unix.h | 4 ++--
 include/net/scm.h     | 1 +
 net/core/scm.c        | 7 +++++++
 net/unix/af_unix.c    | 4 ++--
 net/unix/garbage.c    | 8 ++++----
 5 files changed, 16 insertions(+), 8 deletions(-)

diff --git a/include/net/af_unix.h b/include/net/af_unix.h
index e830c3dff61a..7bb69c9c3c43 100644
--- a/include/net/af_unix.h
+++ b/include/net/af_unix.h
@@ -6,8 +6,8 @@
 #include <linux/mutex.h>
 #include <net/sock.h>
 
-void unix_inflight(struct file *fp);
-void unix_notinflight(struct file *fp);
+void unix_inflight(struct user_struct *user, struct file *fp);
+void unix_notinflight(struct user_struct *user, struct file *fp);
 void unix_gc(void);
 void wait_for_unix_gc(void);
 struct sock *unix_get_socket(struct file *filp);
diff --git a/include/net/scm.h b/include/net/scm.h
index 262532d111f5..59fa93c01d2a 100644
--- a/include/net/scm.h
+++ b/include/net/scm.h
@@ -21,6 +21,7 @@ struct scm_creds {
 struct scm_fp_list {
 	short			count;
 	short			max;
+	struct user_struct	*user;
 	struct file		*fp[SCM_MAX_FD];
 };
 
diff --git a/net/core/scm.c b/net/core/scm.c
index d30eb057fa7b..cad57a1390dd 100644
--- a/net/core/scm.c
+++ b/net/core/scm.c
@@ -87,6 +87,7 @@ static int scm_fp_copy(struct cmsghdr *cmsg, struct scm_fp_list **fplp)
 		*fplp = fpl;
 		fpl->count = 0;
 		fpl->max = SCM_MAX_FD;
+		fpl->user = NULL;
 	}
 	fpp = &fpl->fp[fpl->count];
 
@@ -107,6 +108,10 @@ static int scm_fp_copy(struct cmsghdr *cmsg, struct scm_fp_list **fplp)
 		*fpp++ = file;
 		fpl->count++;
 	}
+
+	if (!fpl->user)
+		fpl->user = get_uid(current_user());
+
 	return num;
 }
 
@@ -119,6 +124,7 @@ void __scm_destroy(struct scm_cookie *scm)
 		scm->fp = NULL;
 		for (i=fpl->count-1; i>=0; i--)
 			fput(fpl->fp[i]);
+		free_uid(fpl->user);
 		kfree(fpl);
 	}
 }
@@ -337,6 +343,7 @@ struct scm_fp_list *scm_fp_dup(struct scm_fp_list *fpl)
 		for (i = 0; i < fpl->count; i++)
 			get_file(fpl->fp[i]);
 		new_fpl->max = new_fpl->count;
+		new_fpl->user = get_uid(fpl->user);
 	}
 	return new_fpl;
 }
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 29b1f4dc48ca..1bd4ba6b6aa4 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -1469,7 +1469,7 @@ static void unix_detach_fds(struct scm_cookie *scm, struct sk_buff *skb)
 	UNIXCB(skb).fp = NULL;
 
 	for (i = scm->fp->count-1; i >= 0; i--)
-		unix_notinflight(scm->fp->fp[i]);
+		unix_notinflight(scm->fp->user, scm->fp->fp[i]);
 }
 
 static void unix_destruct_scm(struct sk_buff *skb)
@@ -1534,7 +1534,7 @@ static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb)
 		return -ENOMEM;
 
 	for (i = scm->fp->count - 1; i >= 0; i--)
-		unix_inflight(scm->fp->fp[i]);
+		unix_inflight(scm->fp->user, scm->fp->fp[i]);
 	return max_level;
 }
 
diff --git a/net/unix/garbage.c b/net/unix/garbage.c
index 58783dcfd35d..1105a60468ac 100644
--- a/net/unix/garbage.c
+++ b/net/unix/garbage.c
@@ -122,7 +122,7 @@ struct sock *unix_get_socket(struct file *filp)
  *	descriptor if it is for an AF_UNIX socket.
  */
 
-void unix_inflight(struct file *fp)
+void unix_inflight(struct user_struct *user, struct file *fp)
 {
 	struct sock *s = unix_get_socket(fp);
 
@@ -139,11 +139,11 @@ void unix_inflight(struct file *fp)
 		}
 		unix_tot_inflight++;
 	}
-	fp->f_cred->user->unix_inflight++;
+	user->unix_inflight++;
 	spin_unlock(&unix_gc_lock);
 }
 
-void unix_notinflight(struct file *fp)
+void unix_notinflight(struct user_struct *user, struct file *fp)
 {
 	struct sock *s = unix_get_socket(fp);
 
@@ -158,7 +158,7 @@ void unix_notinflight(struct file *fp)
 			list_del_init(&u->link);
 		unix_tot_inflight--;
 	}
-	fp->f_cred->user->unix_inflight--;
+	user->unix_inflight--;
 	spin_unlock(&unix_gc_lock);
 }
 
-- 
2.17.1


      parent reply	other threads:[~2018-10-25 14:21 UTC|newest]

Thread overview: 107+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-10-25 14:17 [PATCH AUTOSEL 3.18 01/98] dm thin: restore requested 'error_if_no_space' setting on OODS to WRITE transition Sasha Levin
2018-10-25 14:17 ` [PATCH AUTOSEL 3.18 02/98] ocfs2: fix journal commit deadlock in ocfs2_convert_inline_data_to_extents Sasha Levin
2018-10-25 14:17 ` [PATCH AUTOSEL 3.18 03/98] s390/kvm: REPLACE barrier fixup with READ_ONCE Sasha Levin
2018-10-25 14:17 ` [PATCH AUTOSEL 3.18 04/98] USB: qcserial: Fix support for HP lt4112 LTE/HSPA+ Gobi 4G Modem Sasha Levin
2018-10-26  8:49   ` Johan Hovold
2018-10-26  9:02     ` Bjørn Mork
2018-10-26  9:11       ` Johan Hovold
2018-10-26 10:59     ` Sasha Levin
2018-10-25 14:17 ` [PATCH AUTOSEL 3.18 05/98] cxl: Fix issues when unmapping contexts Sasha Levin
2018-10-25 14:17 ` [PATCH AUTOSEL 3.18 06/98] s390/ftrace/jprobes: Fix conflict between jprobes and function graph tracing Sasha Levin
2018-10-25 14:17 ` [PATCH AUTOSEL 3.18 07/98] mmc: sdhci: restore behavior when setting VDD via external regulator Sasha Levin
2018-10-25 14:17 ` [PATCH AUTOSEL 3.18 08/98] ARM: OMAP5 / DRA7: Fix HYP mode boot for thumb2 build Sasha Levin
2018-10-25 14:17 ` [PATCH AUTOSEL 3.18 09/98] usb: gadget: gadgetfs: fix an oops in ep_write() Sasha Levin
2018-10-25 14:17 ` [PATCH AUTOSEL 3.18 10/98] ahci_xgene: Fix the DMA state machine lockup for the ATA_CMD_PACKET PIO mode command Sasha Levin
2018-10-25 14:17 ` [PATCH AUTOSEL 3.18 11/98] Revert "drm/i915: Fix mutex->owner inspection race under DEBUG_MUTEXES" Sasha Levin
2018-10-25 14:17 ` [PATCH AUTOSEL 3.18 12/98] pinctrl: at91: fix null pointer dereference Sasha Levin
2018-10-25 14:17 ` [PATCH AUTOSEL 3.18 13/98] PCI: Mark Atheros AR9580 to avoid bus reset Sasha Levin
2018-10-25 20:33   ` Tom Psyborg
2018-10-25 14:17 ` [PATCH AUTOSEL 3.18 14/98] ARM: shmobile: r8a7740: Instantiate GIC from C board code in legacy builds Sasha Levin
2018-10-25 14:17 ` [PATCH AUTOSEL 3.18 15/98] usb: musb: Fix a few off-by-one lengths Sasha Levin
2018-10-26 10:47   ` Rasmus Villemoes
2018-10-25 14:17 ` [PATCH AUTOSEL 3.18 16/98] usb: gadget: f_uac1: access freed memory at f_audio_free_inst Sasha Levin
2018-10-25 14:17 ` [PATCH AUTOSEL 3.18 17/98] usb: musb: Fix randconfig build issues for Kconfig options Sasha Levin
2018-10-25 14:17 ` [PATCH AUTOSEL 3.18 18/98] usb: dwc2: gadget: kill requests with 'force' in s3c_hsotg_udc_stop() Sasha Levin
2018-10-25 14:17 ` [PATCH AUTOSEL 3.18 19/98] phy-sun4i-usb: Change disconnect threshold value for sun6i Sasha Levin
2018-10-25 14:17 ` [PATCH AUTOSEL 3.18 20/98] phy: phy-ti-pipe3: fix inconsistent enumeration of PCIe gen2 cards Sasha Levin
2018-10-25 14:17 ` [PATCH AUTOSEL 3.18 21/98] iio: iio: Fix iio_channel_read return if channel havn't info Sasha Levin
2018-10-25 14:17 ` [PATCH AUTOSEL 3.18 22/98] ARM: dra7xx: Fix counter frequency drift for AM572x errata i856 Sasha Levin
2018-10-25 14:17 ` [PATCH AUTOSEL 3.18 23/98] ARM: OMAP2+: Fix n900 board name for legacy user space Sasha Levin
2018-10-25 14:17 ` [PATCH AUTOSEL 3.18 24/98] NFSv4: Cache the NFSv4/v4.1 client owner_id in the struct nfs_client Sasha Levin
2018-10-25 14:17 ` [PATCH AUTOSEL 3.18 25/98] NFSv4/v4.1: Verify the client owner id during trunking detection Sasha Levin
2018-10-25 14:17 ` [PATCH AUTOSEL 3.18 26/98] NFS: Ignore transport protocol when detecting server trunking Sasha Levin
2018-10-25 14:17 ` [PATCH AUTOSEL 3.18 27/98] NFSv4: Remove incorrect check in can_open_delegated() Sasha Levin
2018-10-25 14:17 ` [PATCH AUTOSEL 3.18 28/98] arm: dts: Use pmu_system_controller phandle for dp phy Sasha Levin
2018-10-25 14:17 ` [PATCH AUTOSEL 3.18 29/98] scsi: ->queue_rq can't sleep Sasha Levin
2018-10-25 14:17 ` [PATCH AUTOSEL 3.18 30/98] USB: EHCI: adjust error return code Sasha Levin
2018-10-25 14:17 ` [PATCH AUTOSEL 3.18 31/98] uas: disable UAS on Apricorn SATA dongles Sasha Levin
2018-10-25 14:17 ` [PATCH AUTOSEL 3.18 32/98] usb: host: ehci-tegra: request deferred probe when failing to get phy Sasha Levin
2018-10-25 14:17 ` [PATCH AUTOSEL 3.18 33/98] Revert "tty: Fix pty master poll() after slave closes v2" Sasha Levin
2018-10-25 14:17 ` [PATCH AUTOSEL 3.18 34/98] serial: samsung: Add the support for Exynos5433 SoC Sasha Levin
2018-10-25 14:17 ` [PATCH AUTOSEL 3.18 35/98] mcb: mcb-pci: Only remap the 1st 0x200 bytes of BAR 0 Sasha Levin
2018-10-25 14:17 ` [PATCH AUTOSEL 3.18 36/98] usb: serial: handle -ENODEV quietly in generic_submit_read_urb Sasha Levin
2018-10-26  8:39   ` Johan Hovold
2018-10-26 10:54     ` Sasha Levin
2018-10-25 14:17 ` [PATCH AUTOSEL 3.18 37/98] ARM: at91/dt: sama5d4: fix the timer reg length Sasha Levin
2018-10-25 14:17 ` [PATCH AUTOSEL 3.18 38/98] ARM: at91: sama5d3: dt: correct the sound route Sasha Levin
2018-10-25 14:17 ` [PATCH AUTOSEL 3.18 39/98] ARM: at91/dt: sam9263: Add missing clocks to lcdc node Sasha Levin
2018-10-25 14:17 ` [PATCH AUTOSEL 3.18 40/98] ARM: at91: board-dt-sama5: add phy_fixup to override NAND_Tree Sasha Levin
2018-10-25 14:17 ` [PATCH AUTOSEL 3.18 41/98] fbdev/broadsheetfb: fix memory leak Sasha Levin
2018-10-25 14:17 ` [PATCH AUTOSEL 3.18 42/98] tracing: Fix enabling of syscall events on the command line Sasha Levin
2018-10-25 14:17 ` [PATCH AUTOSEL 3.18 43/98] perf/rapl: Fix sysfs_show() initialization for RAPL PMU Sasha Levin
2018-10-25 14:17 ` [PATCH AUTOSEL 3.18 44/98] perf/x86/intel: Fix bug for "cycles:p" and "cycles:pp" on SLM Sasha Levin
2018-10-25 14:18 ` [PATCH AUTOSEL 3.18 45/98] perf machine: Fix __machine__findnew_thread() error path Sasha Levin
2018-10-25 14:18 ` [PATCH AUTOSEL 3.18 46/98] perf tools: Fix statfs.f_type data type mismatch build error with uclibc Sasha Levin
2018-10-25 14:18 ` [PATCH AUTOSEL 3.18 47/98] perf tools: Avoid build splat for syscall numbers " Sasha Levin
2018-10-25 14:18 ` [PATCH AUTOSEL 3.18 48/98] perf tools: Fix segfault for symbol annotation on TUI Sasha Levin
2018-10-25 14:18 ` [PATCH AUTOSEL 3.18 49/98] drivers: bus: check cci device tree node status Sasha Levin
2018-10-25 14:18 ` [PATCH AUTOSEL 3.18 50/98] ARM: dts: disable CCI on exynos5420 based arndale-octa Sasha Levin
2018-10-25 14:18 ` [PATCH AUTOSEL 3.18 51/98] clk: rockchip: fix deadlock possibility in cpuclk Sasha Levin
2018-10-25 14:18 ` [PATCH AUTOSEL 3.18 52/98] quota: Fix maximum quota limit settings Sasha Levin
2018-10-25 14:18 ` [PATCH AUTOSEL 3.18 53/98] rtnl: don't account unused struct ifla_port_vsi in rtnl_port_size Sasha Levin
2018-10-25 14:18 ` [PATCH AUTOSEL 3.18 54/98] nfs: fix high load average due to callback thread sleeping Sasha Levin
2018-10-25 14:18 ` [PATCH AUTOSEL 3.18 55/98] rcu: Clear need_qs flag to prevent splat Sasha Levin
2018-10-25 15:31   ` Paul E. McKenney
2018-10-25 14:18 ` [PATCH AUTOSEL 3.18 56/98] x86/irq: Check for valid irq descriptor in check_irq_vectors_for_cpu_disable() Sasha Levin
2018-10-25 14:18 ` [PATCH AUTOSEL 3.18 57/98] of/pci: Remove duplicate kfree in of_pci_get_host_bridge_resources() Sasha Levin
2018-10-25 14:18 ` [PATCH AUTOSEL 3.18 58/98] Btrfs: avoid syncing log in the fast fsync path when not necessary Sasha Levin
2018-10-25 14:18 ` [PATCH AUTOSEL 3.18 59/98] pinctrl: imx25: ensure that a pin with id i is at position i in the info array Sasha Levin
2018-10-25 14:18 ` [PATCH AUTOSEL 3.18 60/98] dm: fix AB-BA deadlock in __dm_destroy() Sasha Levin
2018-10-25 14:18 ` [PATCH AUTOSEL 3.18 61/98] arm/arm64: KVM: Take mmap_sem in stage2_unmap_vm Sasha Levin
2018-10-25 14:18 ` [PATCH AUTOSEL 3.18 62/98] net/mlx4_en: Remove dependency between timestamping capability and service_task Sasha Levin
2018-10-25 14:18 ` [PATCH AUTOSEL 3.18 63/98] iommu/vt-d: Fix VM domain ID leak Sasha Levin
2018-10-25 14:18 ` [PATCH AUTOSEL 3.18 64/98] tty: serial: fsl_lpuart: fix clearing of receive flag Sasha Levin
2018-10-25 14:18 ` [PATCH AUTOSEL 3.18 65/98] x86/idle: Restore trace_cpu_idle to mwait_idle() calls Sasha Levin
2018-10-25 14:18 ` [PATCH AUTOSEL 3.18 66/98] ext4: fix an ext3 collapse range regression in xfstests Sasha Levin
2018-10-25 14:18 ` [PATCH AUTOSEL 3.18 67/98] net: ethernet: davicom: fix devicetree irq resource Sasha Levin
2018-10-25 14:18 ` [PATCH AUTOSEL 3.18 68/98] perf bench numa: Fix to show proper convergence stats Sasha Levin
2018-10-25 14:18 ` [PATCH AUTOSEL 3.18 69/98] MIPS: Fix up obsolete cpu_set usage Sasha Levin
2018-10-25 14:18 ` [PATCH AUTOSEL 3.18 70/98] dm9000: Fix irq trigger type setup on non-dt platforms Sasha Levin
2018-10-25 14:18 ` [PATCH AUTOSEL 3.18 71/98] lib: make memzero_explicit more robust against dead store elimination Sasha Levin
2018-10-25 14:18 ` [PATCH AUTOSEL 3.18 72/98] ASoC: dapm: Don't add prefix to widget stream name Sasha Levin
2018-10-25 14:18 ` [PATCH AUTOSEL 3.18 73/98] mtd: blkdevs: fix potential deadlock + lockdep warnings Sasha Levin
2018-10-25 14:18 ` [PATCH AUTOSEL 3.18 74/98] selftests: Introduce a new script to generate tc batch file Sasha Levin
2018-10-25 14:18 ` [PATCH AUTOSEL 3.18 75/98] rtlwifi: rtl8821ae: Fix system lockups on boot Sasha Levin
2018-10-25 14:18 ` [PATCH AUTOSEL 3.18 76/98] rtlwifi: rtl8821ae: Fix " Sasha Levin
2018-10-25 14:18 ` [PATCH AUTOSEL 3.18 77/98] clocksource/exynos_mct: Clear interrupt when cpu is shut down Sasha Levin
2018-10-25 14:18 ` [PATCH AUTOSEL 3.18 78/98] ALSA: hda - Add headset mic support for Acer Aspire V5-573G Sasha Levin
2018-10-25 14:18 ` [PATCH AUTOSEL 3.18 79/98] ALSA: usb-audio: Add a more accurate volume quirk for AudioQuest DragonFly Sasha Levin
2018-10-25 14:18 ` [PATCH AUTOSEL 3.18 80/98] tty: audit: Fix audit source Sasha Levin
2018-10-25 14:18 ` [PATCH AUTOSEL 3.18 81/98] Btrfs: do not ignore errors from btrfs_lookup_xattr in do_setxattr Sasha Levin
2018-10-25 14:18 ` [PATCH AUTOSEL 3.18 82/98] igb: Unpair the queues when changing the number of queues Sasha Levin
2018-10-25 14:18 ` [PATCH AUTOSEL 3.18 83/98] libata: blacklist Micron 500IT SSD with MU01 firmware Sasha Levin
2018-10-25 14:18 ` [PATCH AUTOSEL 3.18 84/98] perf: Fix PERF_EVENT_IOC_PERIOD deadlock Sasha Levin
2018-10-25 14:18 ` [PATCH AUTOSEL 3.18 85/98] mm: migrate: hugetlb: putback destination hugepage to active list Sasha Levin
2018-10-25 14:18 ` [PATCH AUTOSEL 3.18 86/98] Revert "SCSI: Fix NULL pointer dereference in runtime PM" Sasha Levin
2018-10-25 14:18 ` [PATCH AUTOSEL 3.18 87/98] x86/ldt: Fix small LDT allocation for Xen Sasha Levin
2018-10-25 14:18 ` [PATCH AUTOSEL 3.18 88/98] PCI: Fix devfn for VPD access through function 0 Sasha Levin
2018-10-25 14:18 ` [PATCH AUTOSEL 3.18 89/98] vfs: Make sendfile(2) killable even better Sasha Levin
2018-10-25 14:18 ` [PATCH AUTOSEL 3.18 90/98] sctp: translate network order to host order when users get a hmacid Sasha Levin
2018-10-25 14:18 ` [PATCH AUTOSEL 3.18 91/98] iwlwifi: pcie: correctly define 7265-D cfg Sasha Levin
2018-10-25 14:18 ` [PATCH AUTOSEL 3.18 92/98] ovl: fix open in stacked overlay Sasha Levin
2018-10-25 14:18 ` [PATCH AUTOSEL 3.18 93/98] igb: fix NULL derefs due to skipped SR-IOV enabling Sasha Levin
2018-10-25 14:18 ` [PATCH AUTOSEL 3.18 94/98] KEYS: put keyring if install_session_keyring_to_cred() fails Sasha Levin
2018-10-25 14:18 ` [PATCH AUTOSEL 3.18 95/98] USB: hub: fix up early-exit pathway in hub_activate Sasha Levin
2018-10-25 14:18 ` [PATCH AUTOSEL 3.18 96/98] net: fix warnings in 'make htmldocs' by moving macro definition out of field declaration Sasha Levin
2018-10-25 14:18 ` [PATCH AUTOSEL 3.18 97/98] x86/PCI: Mark Broadwell-EP Home Agent 1 as having non-compliant BARs Sasha Levin
2018-10-25 14:18 ` Sasha Levin [this message]

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=20181025141853.214051-98-sashal@kernel.org \
    --to=sashal@kernel.org \
    --cc=davem@davemloft.net \
    --cc=dh.herrmann@gmail.com \
    --cc=hannes@stressinduktion.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=stable@vger.kernel.org \
    --cc=torvalds@linux-foundation.org \
    --cc=w@1wt.eu \
    /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;
as well as URLs for NNTP newsgroup(s).