public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
To: linux-kernel@vger.kernel.org
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	stable@vger.kernel.org, mpb <mpb.mail@gmail.com>,
	Eric Dumazet <eric.dumazet@gmail.com>,
	Hannes Frederic Sowa <hannes@stressinduktion.org>,
	"David S. Miller" <davem@davemloft.net>
Subject: [PATCH 3.12 28/83] inet: prevent leakage of uninitialized memory to user in recv syscalls
Date: Fri,  6 Dec 2013 13:51:18 -0800	[thread overview]
Message-ID: <20131206214642.685736062@linuxfoundation.org> (raw)
In-Reply-To: <20131206214640.002320724@linuxfoundation.org>

3.12-stable review patch.  If anyone has any objections, please let me know.

------------------

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

[ Upstream commit bceaa90240b6019ed73b49965eac7d167610be69 ]

Only update *addr_len when we actually fill in sockaddr, otherwise we
can return uninitialized memory from the stack to the caller in the
recvfrom, recvmmsg and recvmsg syscalls. Drop the the (addr_len == NULL)
checks because we only get called with a valid addr_len pointer either
from sock_common_recvmsg or inet_recvmsg.

If a blocking read waits on a socket which is concurrently shut down we
now return zero and set msg_msgnamelen to 0.

Reported-by: mpb <mpb.mail@gmail.com>
Suggested-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
 net/ieee802154/dgram.c |    3 +--
 net/ipv4/ping.c        |   19 +++++++------------
 net/ipv4/raw.c         |    4 +---
 net/ipv4/udp.c         |    7 +------
 net/ipv6/raw.c         |    4 +---
 net/ipv6/udp.c         |    5 +----
 net/l2tp/l2tp_ip.c     |    4 +---
 net/phonet/datagram.c  |    9 ++++-----
 8 files changed, 17 insertions(+), 38 deletions(-)

--- a/net/ieee802154/dgram.c
+++ b/net/ieee802154/dgram.c
@@ -315,9 +315,8 @@ static int dgram_recvmsg(struct kiocb *i
 	if (saddr) {
 		saddr->family = AF_IEEE802154;
 		saddr->addr = mac_cb(skb)->sa;
-	}
-	if (addr_len)
 		*addr_len = sizeof(*saddr);
+	}
 
 	if (flags & MSG_TRUNC)
 		copied = skb->len;
--- a/net/ipv4/ping.c
+++ b/net/ipv4/ping.c
@@ -827,8 +827,6 @@ int ping_recvmsg(struct kiocb *iocb, str
 {
 	struct inet_sock *isk = inet_sk(sk);
 	int family = sk->sk_family;
-	struct sockaddr_in *sin;
-	struct sockaddr_in6 *sin6;
 	struct sk_buff *skb;
 	int copied, err;
 
@@ -838,13 +836,6 @@ int ping_recvmsg(struct kiocb *iocb, str
 	if (flags & MSG_OOB)
 		goto out;
 
-	if (addr_len) {
-		if (family == AF_INET)
-			*addr_len = sizeof(*sin);
-		else if (family == AF_INET6 && addr_len)
-			*addr_len = sizeof(*sin6);
-	}
-
 	if (flags & MSG_ERRQUEUE) {
 		if (family == AF_INET) {
 			return ip_recv_error(sk, msg, len);
@@ -874,11 +865,13 @@ int ping_recvmsg(struct kiocb *iocb, str
 
 	/* Copy the address and add cmsg data. */
 	if (family == AF_INET) {
-		sin = (struct sockaddr_in *) msg->msg_name;
+		struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name;
+
 		sin->sin_family = AF_INET;
 		sin->sin_port = 0 /* skb->h.uh->source */;
 		sin->sin_addr.s_addr = ip_hdr(skb)->saddr;
 		memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
+		*addr_len = sizeof(*sin);
 
 		if (isk->cmsg_flags)
 			ip_cmsg_recv(msg, skb);
@@ -887,17 +880,19 @@ int ping_recvmsg(struct kiocb *iocb, str
 	} else if (family == AF_INET6) {
 		struct ipv6_pinfo *np = inet6_sk(sk);
 		struct ipv6hdr *ip6 = ipv6_hdr(skb);
-		sin6 = (struct sockaddr_in6 *) msg->msg_name;
+		struct sockaddr_in6 *sin6 =
+			(struct sockaddr_in6 *)msg->msg_name;
+
 		sin6->sin6_family = AF_INET6;
 		sin6->sin6_port = 0;
 		sin6->sin6_addr = ip6->saddr;
-
 		sin6->sin6_flowinfo = 0;
 		if (np->sndflow)
 			sin6->sin6_flowinfo = ip6_flowinfo(ip6);
 
 		sin6->sin6_scope_id = ipv6_iface_scope_id(&sin6->sin6_addr,
 							  IP6CB(skb)->iif);
+		*addr_len = sizeof(*sin6);
 
 		if (inet6_sk(sk)->rxopt.all)
 			pingv6_ops.ip6_datagram_recv_ctl(sk, msg, skb);
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -694,9 +694,6 @@ static int raw_recvmsg(struct kiocb *ioc
 	if (flags & MSG_OOB)
 		goto out;
 
-	if (addr_len)
-		*addr_len = sizeof(*sin);
-
 	if (flags & MSG_ERRQUEUE) {
 		err = ip_recv_error(sk, msg, len);
 		goto out;
@@ -724,6 +721,7 @@ static int raw_recvmsg(struct kiocb *ioc
 		sin->sin_addr.s_addr = ip_hdr(skb)->saddr;
 		sin->sin_port = 0;
 		memset(&sin->sin_zero, 0, sizeof(sin->sin_zero));
+		*addr_len = sizeof(*sin);
 	}
 	if (inet->cmsg_flags)
 		ip_cmsg_recv(msg, skb);
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -1209,12 +1209,6 @@ int udp_recvmsg(struct kiocb *iocb, stru
 	int is_udplite = IS_UDPLITE(sk);
 	bool slow;
 
-	/*
-	 *	Check any passed addresses
-	 */
-	if (addr_len)
-		*addr_len = sizeof(*sin);
-
 	if (flags & MSG_ERRQUEUE)
 		return ip_recv_error(sk, msg, len);
 
@@ -1276,6 +1270,7 @@ try_again:
 		sin->sin_port = udp_hdr(skb)->source;
 		sin->sin_addr.s_addr = ip_hdr(skb)->saddr;
 		memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
+		*addr_len = sizeof(*sin);
 	}
 	if (inet->cmsg_flags)
 		ip_cmsg_recv(msg, skb);
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -466,9 +466,6 @@ static int rawv6_recvmsg(struct kiocb *i
 	if (flags & MSG_OOB)
 		return -EOPNOTSUPP;
 
-	if (addr_len)
-		*addr_len=sizeof(*sin6);
-
 	if (flags & MSG_ERRQUEUE)
 		return ipv6_recv_error(sk, msg, len);
 
@@ -507,6 +504,7 @@ static int rawv6_recvmsg(struct kiocb *i
 		sin6->sin6_flowinfo = 0;
 		sin6->sin6_scope_id = ipv6_iface_scope_id(&sin6->sin6_addr,
 							  IP6CB(skb)->iif);
+		*addr_len = sizeof(*sin6);
 	}
 
 	sock_recv_ts_and_drops(msg, sk, skb);
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -374,9 +374,6 @@ int udpv6_recvmsg(struct kiocb *iocb, st
 	int is_udp4;
 	bool slow;
 
-	if (addr_len)
-		*addr_len = sizeof(struct sockaddr_in6);
-
 	if (flags & MSG_ERRQUEUE)
 		return ipv6_recv_error(sk, msg, len);
 
@@ -462,7 +459,7 @@ try_again:
 				ipv6_iface_scope_id(&sin6->sin6_addr,
 						    IP6CB(skb)->iif);
 		}
-
+		*addr_len = sizeof(*sin6);
 	}
 	if (is_udp4) {
 		if (inet->cmsg_flags)
--- a/net/l2tp/l2tp_ip.c
+++ b/net/l2tp/l2tp_ip.c
@@ -518,9 +518,6 @@ static int l2tp_ip_recvmsg(struct kiocb
 	if (flags & MSG_OOB)
 		goto out;
 
-	if (addr_len)
-		*addr_len = sizeof(*sin);
-
 	skb = skb_recv_datagram(sk, flags, noblock, &err);
 	if (!skb)
 		goto out;
@@ -543,6 +540,7 @@ static int l2tp_ip_recvmsg(struct kiocb
 		sin->sin_addr.s_addr = ip_hdr(skb)->saddr;
 		sin->sin_port = 0;
 		memset(&sin->sin_zero, 0, sizeof(sin->sin_zero));
+		*addr_len = sizeof(*sin);
 	}
 	if (inet->cmsg_flags)
 		ip_cmsg_recv(msg, skb);
--- a/net/phonet/datagram.c
+++ b/net/phonet/datagram.c
@@ -139,9 +139,6 @@ static int pn_recvmsg(struct kiocb *iocb
 			MSG_CMSG_COMPAT))
 		goto out_nofree;
 
-	if (addr_len)
-		*addr_len = sizeof(sa);
-
 	skb = skb_recv_datagram(sk, flags, noblock, &rval);
 	if (skb == NULL)
 		goto out_nofree;
@@ -162,8 +159,10 @@ static int pn_recvmsg(struct kiocb *iocb
 
 	rval = (flags & MSG_TRUNC) ? skb->len : copylen;
 
-	if (msg->msg_name != NULL)
-		memcpy(msg->msg_name, &sa, sizeof(struct sockaddr_pn));
+	if (msg->msg_name != NULL) {
+		memcpy(msg->msg_name, &sa, sizeof(sa));
+		*addr_len = sizeof(sa);
+	}
 
 out:
 	skb_free_datagram(sk, skb);



  parent reply	other threads:[~2013-12-06 22:39 UTC|newest]

Thread overview: 90+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-12-06 21:50 [PATCH 3.12 00/83] 3.12.4-stable review Greg Kroah-Hartman
2013-12-06 21:50 ` [PATCH 3.12 01/83] net: mv643xx_eth: Add missing phy_addr_set in DT mode Greg Kroah-Hartman
2013-12-06 21:50 ` [PATCH 3.12 02/83] net: mv643xx_eth: potential NULL dereference in probe() Greg Kroah-Hartman
2013-12-06 21:50 ` [PATCH 3.12 03/83] ipv6: fix headroom calculation in udp6_ufo_fragment Greg Kroah-Hartman
2013-12-06 21:50 ` [PATCH 3.12 04/83] bonding: RCUify bond_set_rx_mode() Greg Kroah-Hartman
2013-12-06 21:50 ` [PATCH 3.12 05/83] net: x86: bpf: dont forget to free sk_filter (v2) Greg Kroah-Hartman
2013-12-06 21:50 ` [PATCH 3.12 06/83] net/mlx4_en: Fixed crash when port type is changed Greg Kroah-Hartman
2013-12-06 21:50 ` [PATCH 3.12 07/83] net: Fix "ip rule delete table 256" Greg Kroah-Hartman
2013-12-06 21:50 ` [PATCH 3.12 08/83] ipv6: use rt6_get_dflt_router to get default router in rt6_route_rcv Greg Kroah-Hartman
2013-12-06 21:50 ` [PATCH 3.12 09/83] ipv6: protect for_each_sk_fl_rcu in mem_check with rcu_read_lock_bh Greg Kroah-Hartman
2013-12-06 21:51 ` [PATCH 3.12 10/83] random32: fix off-by-one in seeding requirement Greg Kroah-Hartman
2013-12-06 21:51 ` [PATCH 3.12 11/83] bonding: dont permit to use ARP monitoring in 802.3ad mode Greg Kroah-Hartman
2013-12-06 21:51 ` [PATCH 3.12 12/83] usbnet: fix status interrupt urb handling Greg Kroah-Hartman
2013-12-06 21:51 ` [PATCH 3.12 13/83] core/dev: do not ignore dmac in dev_forward_skb() Greg Kroah-Hartman
2013-12-06 21:51 ` [PATCH 3.12 14/83] 6lowpan: Uncompression of traffic class field was incorrect Greg Kroah-Hartman
2013-12-06 21:51 ` [PATCH 3.12 15/83] tuntap: limit head length of skb allocated Greg Kroah-Hartman
2013-12-06 21:51 ` [PATCH 3.12 16/83] macvtap: " Greg Kroah-Hartman
2013-12-06 21:51 ` [PATCH 3.12 17/83] tcp: tsq: restore minimal amount of queueing Greg Kroah-Hartman
2013-12-06 21:51 ` [PATCH 3.12 18/83] bonding: fix two race conditions in bond_store_updelay/downdelay Greg Kroah-Hartman
2013-12-06 21:51 ` [PATCH 3.12 19/83] net-tcp: fix panic in tcp_fastopen_cache_set() Greg Kroah-Hartman
2013-12-06 21:51 ` [PATCH 3.12 20/83] sit: fix use after free of fb_tunnel_dev Greg Kroah-Hartman
2013-12-06 21:51 ` [PATCH 3.12 21/83] isdnloop: use strlcpy() instead of strcpy() Greg Kroah-Hartman
2013-12-06 21:51 ` [PATCH 3.12 22/83] ip6tnl: fix use after free of fb_tnl_dev Greg Kroah-Hartman
2013-12-06 21:51 ` [PATCH 3.12 23/83] pkt_sched: fq: change classification of control packets Greg Kroah-Hartman
2013-12-06 21:51 ` [PATCH 3.12 24/83] connector: improved unaligned access error fix Greg Kroah-Hartman
2013-12-06 21:51 ` [PATCH 3.12 25/83] ipv4: fix possible seqlock deadlock Greg Kroah-Hartman
2013-12-06 21:51 ` [PATCH 3.12 26/83] pkt_sched: fq: warn users using defrate Greg Kroah-Hartman
2013-12-06 21:51 ` [PATCH 3.12 27/83] pkt_sched: fq: fix pacing for small frames Greg Kroah-Hartman
2013-12-06 21:51 ` Greg Kroah-Hartman [this message]
2013-12-06 21:51 ` [PATCH 3.12 29/83] ping: prevent NULL pointer dereference on write to msg_name Greg Kroah-Hartman
2013-12-06 21:51 ` [PATCH 3.12 30/83] net: rework recvmsg handler msg_name and msg_namelen logic Greg Kroah-Hartman
2013-12-06 21:51 ` [PATCH 3.12 31/83] net: add BUG_ON if kernel advertises msg_namelen > sizeof(struct sockaddr_storage) Greg Kroah-Hartman
2013-12-06 21:51 ` [PATCH 3.12 32/83] inet: fix addr_len/msg->msg_namelen assignment in recv_error and rxpmtu functions Greg Kroah-Hartman
2013-12-06 21:51 ` [PATCH 3.12 33/83] net: clamp ->msg_namelen instead of returning an error Greg Kroah-Hartman
2013-12-06 21:51 ` [PATCH 3.12 34/83] ipv6: fix leaking uninitialized port number of offender sockaddr Greg Kroah-Hartman
2013-12-06 21:51 ` [PATCH 3.12 35/83] ipv6: Fix inet6_init() cleanup order Greg Kroah-Hartman
2013-12-06 21:51 ` [PATCH 3.12 36/83] ip6_output: fragment outgoing reassembled skb properly Greg Kroah-Hartman
2013-12-06 21:51 ` [PATCH 3.12 37/83] netfilter: push reasm skb through instead of original frag skbs Greg Kroah-Hartman
2013-12-06 21:51 ` [PATCH 3.12 38/83] xfrm: Release dst if this dst is improper for vti tunnel Greg Kroah-Hartman
2013-12-06 21:51 ` [PATCH 3.12 39/83] atm: idt77252: fix dev refcnt leak Greg Kroah-Hartman
2013-12-06 21:51 ` [PATCH 3.12 40/83] tcp: dont update snd_nxt, when a socket is switched from repair mode Greg Kroah-Hartman
2013-12-06 21:51 ` [PATCH 3.12 41/83] ipv4: fix race in concurrent ip_route_input_slow() Greg Kroah-Hartman
2013-12-06 21:51 ` [PATCH 3.12 42/83] net: core: Always propagate flag changes to interfaces Greg Kroah-Hartman
2013-12-06 21:51 ` [PATCH 3.12 43/83] bridge: flush brs address entry in fdb when remove the bridge dev Greg Kroah-Hartman
2013-12-06 21:51 ` [PATCH 3.12 44/83] packet: fix use after free race in send path when dev is released Greg Kroah-Hartman
2013-12-06 21:51 ` [PATCH 3.12 45/83] af_packet: block BH in prb_shutdown_retire_blk_timer() Greg Kroah-Hartman
2013-12-06 21:51 ` [PATCH 3.12 46/83] gso: handle new frag_list of frags GRO packets Greg Kroah-Hartman
2013-12-06 21:51 ` [PATCH 3.12 47/83] gro: Only verify TCP checksums for candidates Greg Kroah-Hartman
2013-12-06 21:51 ` [PATCH 3.12 48/83] gro: Clean up tcpX_gro_receive checksum verification Greg Kroah-Hartman
2013-12-06 21:51 ` [PATCH 3.12 49/83] sch_tbf: handle too small burst Greg Kroah-Hartman
2013-12-06 21:51 ` [PATCH 3.12 50/83] xen-netback: include definition of csum_ipv6_magic Greg Kroah-Hartman
2013-12-06 21:51 ` [PATCH 3.12 51/83] via-velocity: fix netif_receive_skb use in irq disabled section Greg Kroah-Hartman
2013-12-06 21:51 ` [PATCH 3.12 52/83] r8169: check ALDPS bit and disable it if enabled for the 8168g Greg Kroah-Hartman
2013-12-06 21:51 ` [PATCH 3.12 53/83] net: 8139cp: fix a BUG_ON triggered by wrong bytes_compl Greg Kroah-Hartman
2013-12-06 21:51 ` [PATCH 3.12 54/83] net: smc91: fix crash regression on the versatile Greg Kroah-Hartman
2013-12-06 21:51 ` [PATCH 3.12 55/83] net: update consumers of MSG_MORE to recognize MSG_SENDPAGE_NOTLAST Greg Kroah-Hartman
2013-12-06 21:51 ` [PATCH 3.12 56/83] team: fix master carrier set when user linkup is enabled Greg Kroah-Hartman
2013-12-06 21:51 ` [PATCH 3.12 57/83] inet: fix possible seqlock deadlocks Greg Kroah-Hartman
2013-12-06 21:51 ` [PATCH 3.12 58/83] ipv6: fix possible seqlock deadlock in ip6_finish_output2 Greg Kroah-Hartman
2013-12-06 21:51 ` [PATCH 3.12 59/83] {pktgen, xfrm} Update IPv4 header total len and checksum after tranformation Greg Kroah-Hartman
2013-12-06 21:51 ` [PATCH 3.12 60/83] xfrm: Fix null pointer dereference when decoding sessions Greg Kroah-Hartman
2013-12-06 21:51 ` [PATCH 3.12 61/83] xfs: add capability check to free eofblocks ioctl Greg Kroah-Hartman
2013-12-06 21:51 ` [PATCH 3.12 62/83] mm: numa: return the number of base pages altered by protection changes Greg Kroah-Hartman
2013-12-06 21:51 ` [PATCH 3.12 63/83] md/raid5: Use conf->device_lock protect changing of multi-thread resources Greg Kroah-Hartman
2013-12-06 21:51 ` [PATCH 3.12 64/83] usb: musb: davinci: fix resources passed to MUSB driver for DM6467 Greg Kroah-Hartman
2013-12-06 21:51 ` [PATCH 3.12 65/83] usb: wusbcore: change WA_SEGS_MAX to a legal value Greg Kroah-Hartman
2013-12-06 21:51 ` [PATCH 3.12 66/83] video: kyro: fix incorrect sizes when copying to userspace Greg Kroah-Hartman
2013-12-06 21:51 ` [PATCH 3.12 67/83] HID: lg: fix Report Descriptor for Logitech MOMO Force (Black) Greg Kroah-Hartman
2013-12-06 21:51 ` [PATCH 3.12 68/83] HID: hid-elo: some systems cannot stomach work around Greg Kroah-Hartman
2013-12-06 21:51 ` [PATCH 3.12 69/83] iommu/vt-d: Fixed interaction of VFIO_IOMMU_MAP_DMA with IOMMU address limits Greg Kroah-Hartman
2013-12-06 21:52 ` [PATCH 3.12 70/83] iommu: Remove stack trace from broken irq remapping warning Greg Kroah-Hartman
2013-12-06 21:52 ` [PATCH 3.12 71/83] rt2800: add support for radio chip RF3070 Greg Kroah-Hartman
2013-12-06 21:52 ` [PATCH 3.12 72/83] elevator: Fix a race in elevator switching and md device initialization Greg Kroah-Hartman
2013-12-06 21:52 ` [PATCH 3.12 73/83] elevator: acquire q->sysfs_lock in elevator_change() Greg Kroah-Hartman
2013-12-06 21:52 ` [PATCH 3.12 74/83] ntp: Make periodic RTC update more reliable Greg Kroah-Hartman
2013-12-06 21:52 ` [PATCH 3.12 75/83] aio: Fix a trinity splat Greg Kroah-Hartman
2013-12-06 21:52 ` [PATCH 3.12 76/83] take anon inode allocation to libfs.c Greg Kroah-Hartman
2013-12-06 21:52 ` [PATCH 3.12 77/83] rework aio migrate pages to use aio fs Greg Kroah-Hartman
2013-12-06 21:52 ` [PATCH 3.12 78/83] aio: checking for NULL instead of IS_ERR Greg Kroah-Hartman
2013-12-06 21:52 ` [PATCH 3.12 79/83] aio: prevent double free in ioctx_alloc Greg Kroah-Hartman
2013-12-06 21:52 ` [PATCH 3.12 80/83] aio: nullify aio->ring_pages after freeing it Greg Kroah-Hartman
2013-12-06 21:52 ` [PATCH 3.12 81/83] aio: clean up aio ring in the fail path Greg Kroah-Hartman
2013-12-06 21:52 ` [PATCH 3.12 82/83] drm/radeon/audio: improve ACR calculation Greg Kroah-Hartman
2013-12-06 21:52 ` [PATCH 3.12 83/83] drm/radeon/audio: correct ACR table Greg Kroah-Hartman
2013-12-06 22:52 ` [PATCH 3.12 00/83] 3.12.4-stable review Holger Hoffstätte
2013-12-07 17:01   ` Greg KH
2013-12-07  6:44 ` Guenter Roeck
2013-12-07 17:00   ` Greg Kroah-Hartman
2013-12-07 22:15 ` Shuah Khan
2013-12-07 23:17   ` Greg Kroah-Hartman

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=20131206214642.685736062@linuxfoundation.org \
    --to=gregkh@linuxfoundation.org \
    --cc=davem@davemloft.net \
    --cc=eric.dumazet@gmail.com \
    --cc=hannes@stressinduktion.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mpb.mail@gmail.com \
    --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