public inbox for gentoo-commits@lists.gentoo.org
 help / color / mirror / Atom feed
From: "Anthony G. Basile" <blueness@gentoo.org>
To: gentoo-commits@lists.gentoo.org
Subject: [gentoo-commits] proj/hardened-dev:musl commit in: app-emulation/qemu/files/, app-emulation/qemu/
Date: Mon,  8 Jun 2015 12:26:49 +0000 (UTC)	[thread overview]
Message-ID: <1433766459.dd8f541bb891cc198527837f2eedb81594efb1f3.blueness@gentoo> (raw)

commit:     dd8f541bb891cc198527837f2eedb81594efb1f3
Author:     Felix Janda <felix.janda <AT> posteo <DOT> de>
AuthorDate: Sun Jun  7 19:17:51 2015 +0000
Commit:     Anthony G. Basile <blueness <AT> gentoo <DOT> org>
CommitDate: Mon Jun  8 12:27:39 2015 +0000
URL:        https://gitweb.gentoo.org/proj/hardened-dev.git/commit/?id=dd8f541b

app-emulation/qemu: Bump to 2.2.0

 .../qemu/files/qemu-2.2.1-CVE-2015-1779-1.patch    | 241 +++++++++++++++++++++
 .../qemu/files/qemu-2.2.1-CVE-2015-1779-2.patch    |  58 +++++
 .../qemu/files/qemu-2.3.0-CVE-2015-3456.patch      |  86 ++++++++
 ...qemu-2.2.0-r99.ebuild => qemu-2.2.1-r99.ebuild} |  21 +-
 4 files changed, 397 insertions(+), 9 deletions(-)

diff --git a/app-emulation/qemu/files/qemu-2.2.1-CVE-2015-1779-1.patch b/app-emulation/qemu/files/qemu-2.2.1-CVE-2015-1779-1.patch
new file mode 100644
index 0000000..35ef8fd
--- /dev/null
+++ b/app-emulation/qemu/files/qemu-2.2.1-CVE-2015-1779-1.patch
@@ -0,0 +1,241 @@
+From a2bebfd6e09d285aa793cae3fb0fc3a39a9fee6e Mon Sep 17 00:00:00 2001
+From: "Daniel P. Berrange" <berrange@redhat.com>
+Date: Mon, 23 Mar 2015 22:58:21 +0000
+Subject: [PATCH] CVE-2015-1779: incrementally decode websocket frames
+
+The logic for decoding websocket frames wants to fully
+decode the frame header and payload, before allowing the
+VNC server to see any of the payload data. There is no
+size limit on websocket payloads, so this allows a
+malicious network client to consume 2^64 bytes in memory
+in QEMU. It can trigger this denial of service before
+the VNC server even performs any authentication.
+
+The fix is to decode the header, and then incrementally
+decode the payload data as it is needed. With this fix
+the websocket decoder will allow at most 4k of data to
+be buffered before decoding and processing payload.
+
+Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
+
+[ kraxel: fix frequent spurious disconnects, suggested by Peter Maydell ]
+
+  @@ -361,7 +361,7 @@ int vncws_decode_frame_payload(Buffer *input,
+  -        *payload_size = input->offset;
+  +        *payload_size = *payload_remain;
+
+[ kraxel: fix 32bit build ]
+
+  @@ -306,7 +306,7 @@ struct VncState
+  -    uint64_t ws_payload_remain;
+  +    size_t ws_payload_remain;
+
+Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
+---
+ ui/vnc-ws.c | 105 ++++++++++++++++++++++++++++++++++++++++--------------------
+ ui/vnc-ws.h |   9 ++++--
+ ui/vnc.h    |   2 ++
+ 3 files changed, 80 insertions(+), 36 deletions(-)
+
+diff --git a/ui/vnc-ws.c b/ui/vnc-ws.c
+index 85dbb7e..0b7de4e 100644
+--- a/ui/vnc-ws.c
++++ b/ui/vnc-ws.c
+@@ -107,7 +107,7 @@ long vnc_client_read_ws(VncState *vs)
+ {
+     int ret, err;
+     uint8_t *payload;
+-    size_t payload_size, frame_size;
++    size_t payload_size, header_size;
+     VNC_DEBUG("Read websocket %p size %zd offset %zd\n", vs->ws_input.buffer,
+             vs->ws_input.capacity, vs->ws_input.offset);
+     buffer_reserve(&vs->ws_input, 4096);
+@@ -117,18 +117,39 @@ long vnc_client_read_ws(VncState *vs)
+     }
+     vs->ws_input.offset += ret;
+ 
+-    /* make sure that nothing is left in the ws_input buffer */
++    ret = 0;
++    /* consume as much of ws_input buffer as possible */
+     do {
+-        err = vncws_decode_frame(&vs->ws_input, &payload,
+-                              &payload_size, &frame_size);
+-        if (err <= 0) {
+-            return err;
++        if (vs->ws_payload_remain == 0) {
++            err = vncws_decode_frame_header(&vs->ws_input,
++                                            &header_size,
++                                            &vs->ws_payload_remain,
++                                            &vs->ws_payload_mask);
++            if (err <= 0) {
++                return err;
++            }
++
++            buffer_advance(&vs->ws_input, header_size);
+         }
++        if (vs->ws_payload_remain != 0) {
++            err = vncws_decode_frame_payload(&vs->ws_input,
++                                             &vs->ws_payload_remain,
++                                             &vs->ws_payload_mask,
++                                             &payload,
++                                             &payload_size);
++            if (err < 0) {
++                return err;
++            }
++            if (err == 0) {
++                return ret;
++            }
++            ret += err;
+ 
+-        buffer_reserve(&vs->input, payload_size);
+-        buffer_append(&vs->input, payload, payload_size);
++            buffer_reserve(&vs->input, payload_size);
++            buffer_append(&vs->input, payload, payload_size);
+ 
+-        buffer_advance(&vs->ws_input, frame_size);
++            buffer_advance(&vs->ws_input, payload_size);
++        }
+     } while (vs->ws_input.offset > 0);
+ 
+     return ret;
+@@ -265,15 +286,14 @@ void vncws_encode_frame(Buffer *output, const void *payload,
+     buffer_append(output, payload, payload_size);
+ }
+ 
+-int vncws_decode_frame(Buffer *input, uint8_t **payload,
+-                           size_t *payload_size, size_t *frame_size)
++int vncws_decode_frame_header(Buffer *input,
++                              size_t *header_size,
++                              size_t *payload_remain,
++                              WsMask *payload_mask)
+ {
+     unsigned char opcode = 0, fin = 0, has_mask = 0;
+-    size_t header_size = 0;
+-    uint32_t *payload32;
++    size_t payload_len;
+     WsHeader *header = (WsHeader *)input->buffer;
+-    WsMask mask;
+-    int i;
+ 
+     if (input->offset < WS_HEAD_MIN_LEN + 4) {
+         /* header not complete */
+@@ -283,7 +303,7 @@ int vncws_decode_frame(Buffer *input, uint8_t **payload,
+     fin = (header->b0 & 0x80) >> 7;
+     opcode = header->b0 & 0x0f;
+     has_mask = (header->b1 & 0x80) >> 7;
+-    *payload_size = header->b1 & 0x7f;
++    payload_len = header->b1 & 0x7f;
+ 
+     if (opcode == WS_OPCODE_CLOSE) {
+         /* disconnect */
+@@ -300,40 +320,57 @@ int vncws_decode_frame(Buffer *input, uint8_t **payload,
+         return -2;
+     }
+ 
+-    if (*payload_size < 126) {
+-        header_size = 6;
+-        mask = header->u.m;
+-    } else if (*payload_size == 126 && input->offset >= 8) {
+-        *payload_size = be16_to_cpu(header->u.s16.l16);
+-        header_size = 8;
+-        mask = header->u.s16.m16;
+-    } else if (*payload_size == 127 && input->offset >= 14) {
+-        *payload_size = be64_to_cpu(header->u.s64.l64);
+-        header_size = 14;
+-        mask = header->u.s64.m64;
++    if (payload_len < 126) {
++        *payload_remain = payload_len;
++        *header_size = 6;
++        *payload_mask = header->u.m;
++    } else if (payload_len == 126 && input->offset >= 8) {
++        *payload_remain = be16_to_cpu(header->u.s16.l16);
++        *header_size = 8;
++        *payload_mask = header->u.s16.m16;
++    } else if (payload_len == 127 && input->offset >= 14) {
++        *payload_remain = be64_to_cpu(header->u.s64.l64);
++        *header_size = 14;
++        *payload_mask = header->u.s64.m64;
+     } else {
+         /* header not complete */
+         return 0;
+     }
+ 
+-    *frame_size = header_size + *payload_size;
++    return 1;
++}
++
++int vncws_decode_frame_payload(Buffer *input,
++                               size_t *payload_remain, WsMask *payload_mask,
++                               uint8_t **payload, size_t *payload_size)
++{
++    size_t i;
++    uint32_t *payload32;
+ 
+-    if (input->offset < *frame_size) {
+-        /* frame not complete */
++    *payload = input->buffer;
++    /* If we aren't at the end of the payload, then drop
++     * off the last bytes, so we're always multiple of 4
++     * for purpose of unmasking, except at end of payload
++     */
++    if (input->offset < *payload_remain) {
++        *payload_size = input->offset - (input->offset % 4);
++    } else {
++        *payload_size = *payload_remain;
++    }
++    if (*payload_size == 0) {
+         return 0;
+     }
+-
+-    *payload = input->buffer + header_size;
++    *payload_remain -= *payload_size;
+ 
+     /* unmask frame */
+     /* process 1 frame (32 bit op) */
+     payload32 = (uint32_t *)(*payload);
+     for (i = 0; i < *payload_size / 4; i++) {
+-        payload32[i] ^= mask.u;
++        payload32[i] ^= payload_mask->u;
+     }
+     /* process the remaining bytes (if any) */
+     for (i *= 4; i < *payload_size; i++) {
+-        (*payload)[i] ^= mask.c[i % 4];
++        (*payload)[i] ^= payload_mask->c[i % 4];
+     }
+ 
+     return 1;
+diff --git a/ui/vnc-ws.h b/ui/vnc-ws.h
+index ef229b7..14d4230 100644
+--- a/ui/vnc-ws.h
++++ b/ui/vnc-ws.h
+@@ -83,7 +83,12 @@ long vnc_client_read_ws(VncState *vs);
+ void vncws_process_handshake(VncState *vs, uint8_t *line, size_t size);
+ void vncws_encode_frame(Buffer *output, const void *payload,
+             const size_t payload_size);
+-int vncws_decode_frame(Buffer *input, uint8_t **payload,
+-                               size_t *payload_size, size_t *frame_size);
++int vncws_decode_frame_header(Buffer *input,
++                              size_t *header_size,
++                              size_t *payload_remain,
++                              WsMask *payload_mask);
++int vncws_decode_frame_payload(Buffer *input,
++                               size_t *payload_remain, WsMask *payload_mask,
++                               uint8_t **payload, size_t *payload_size);
+ 
+ #endif /* __QEMU_UI_VNC_WS_H */
+diff --git a/ui/vnc.h b/ui/vnc.h
+index e19ac39..3f7c6a9 100644
+--- a/ui/vnc.h
++++ b/ui/vnc.h
+@@ -306,6 +306,8 @@ struct VncState
+ #ifdef CONFIG_VNC_WS
+     Buffer ws_input;
+     Buffer ws_output;
++    size_t ws_payload_remain;
++    WsMask ws_payload_mask;
+ #endif
+     /* current output mode information */
+     VncWritePixels *write_pixels;
+-- 
+2.3.5
+

diff --git a/app-emulation/qemu/files/qemu-2.2.1-CVE-2015-1779-2.patch b/app-emulation/qemu/files/qemu-2.2.1-CVE-2015-1779-2.patch
new file mode 100644
index 0000000..c7a8c8b
--- /dev/null
+++ b/app-emulation/qemu/files/qemu-2.2.1-CVE-2015-1779-2.patch
@@ -0,0 +1,58 @@
+From 2cdb5e142fb93e875fa53c52864ef5eb8d5d8b41 Mon Sep 17 00:00:00 2001
+From: "Daniel P. Berrange" <berrange@redhat.com>
+Date: Mon, 23 Mar 2015 22:58:22 +0000
+Subject: [PATCH] CVE-2015-1779: limit size of HTTP headers from websockets
+ clients
+
+The VNC server websockets decoder will read and buffer data from
+websockets clients until it sees the end of the HTTP headers,
+as indicated by \r\n\r\n. In theory this allows a malicious to
+trick QEMU into consuming an arbitrary amount of RAM. In practice,
+because QEMU runs g_strstr_len() across the buffered header data,
+it will spend increasingly long burning CPU time searching for
+the substring match and less & less time reading data. So while
+this does cause arbitrary memory growth, the bigger problem is
+that QEMU will be burning 100% of available CPU time.
+
+A novnc websockets client typically sends headers of around
+512 bytes in length. As such it is reasonable to place a 4096
+byte limit on the amount of data buffered while searching for
+the end of HTTP headers.
+
+Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
+Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
+---
+ ui/vnc-ws.c | 10 ++++++++--
+ 1 file changed, 8 insertions(+), 2 deletions(-)
+
+diff --git a/ui/vnc-ws.c b/ui/vnc-ws.c
+index 0b7de4e..62eb97f 100644
+--- a/ui/vnc-ws.c
++++ b/ui/vnc-ws.c
+@@ -81,8 +81,11 @@ void vncws_handshake_read(void *opaque)
+     VncState *vs = opaque;
+     uint8_t *handshake_end;
+     long ret;
+-    buffer_reserve(&vs->ws_input, 4096);
+-    ret = vnc_client_read_buf(vs, buffer_end(&vs->ws_input), 4096);
++    /* Typical HTTP headers from novnc are 512 bytes, so limiting
++     * total header size to 4096 is easily enough. */
++    size_t want = 4096 - vs->ws_input.offset;
++    buffer_reserve(&vs->ws_input, want);
++    ret = vnc_client_read_buf(vs, buffer_end(&vs->ws_input), want);
+ 
+     if (!ret) {
+         if (vs->csock == -1) {
+@@ -99,6 +102,9 @@ void vncws_handshake_read(void *opaque)
+         vncws_process_handshake(vs, vs->ws_input.buffer, vs->ws_input.offset);
+         buffer_advance(&vs->ws_input, handshake_end - vs->ws_input.buffer +
+                 strlen(WS_HANDSHAKE_END));
++    } else if (vs->ws_input.offset >= 4096) {
++        VNC_DEBUG("End of headers not found in first 4096 bytes\n");
++        vnc_client_error(vs);
+     }
+ }
+ 
+-- 
+2.3.5
+

diff --git a/app-emulation/qemu/files/qemu-2.3.0-CVE-2015-3456.patch b/app-emulation/qemu/files/qemu-2.3.0-CVE-2015-3456.patch
new file mode 100644
index 0000000..87697d0
--- /dev/null
+++ b/app-emulation/qemu/files/qemu-2.3.0-CVE-2015-3456.patch
@@ -0,0 +1,86 @@
+https://bugs.gentoo.org/549404
+
+From e907746266721f305d67bc0718795fedee2e824c Mon Sep 17 00:00:00 2001
+From: Petr Matousek <pmatouse@redhat.com>
+Date: Wed, 6 May 2015 09:48:59 +0200
+Subject: [PATCH] fdc: force the fifo access to be in bounds of the allocated buffer
+
+During processing of certain commands such as FD_CMD_READ_ID and
+FD_CMD_DRIVE_SPECIFICATION_COMMAND the fifo memory access could
+get out of bounds leading to memory corruption with values coming
+from the guest.
+
+Fix this by making sure that the index is always bounded by the
+allocated memory.
+
+This is CVE-2015-3456.
+
+Signed-off-by: Petr Matousek <pmatouse@redhat.com>
+Reviewed-by: John Snow <jsnow@redhat.com>
+Signed-off-by: John Snow <jsnow@redhat.com>
+---
+ hw/block/fdc.c |   17 +++++++++++------
+ 1 files changed, 11 insertions(+), 6 deletions(-)
+
+diff --git a/hw/block/fdc.c b/hw/block/fdc.c
+index f72a392..d8a8edd 100644
+--- a/hw/block/fdc.c
++++ b/hw/block/fdc.c
+@@ -1497,7 +1497,7 @@ static uint32_t fdctrl_read_data(FDCtrl *fdctrl)
+ {
+     FDrive *cur_drv;
+     uint32_t retval = 0;
+-    int pos;
++    uint32_t pos;
+ 
+     cur_drv = get_cur_drv(fdctrl);
+     fdctrl->dsr &= ~FD_DSR_PWRDOWN;
+@@ -1506,8 +1506,8 @@ static uint32_t fdctrl_read_data(FDCtrl *fdctrl)
+         return 0;
+     }
+     pos = fdctrl->data_pos;
++    pos %= FD_SECTOR_LEN;
+     if (fdctrl->msr & FD_MSR_NONDMA) {
+-        pos %= FD_SECTOR_LEN;
+         if (pos == 0) {
+             if (fdctrl->data_pos != 0)
+                 if (!fdctrl_seek_to_next_sect(fdctrl, cur_drv)) {
+@@ -1852,10 +1852,13 @@ static void fdctrl_handle_option(FDCtrl *fdctrl, int direction)
+ static void fdctrl_handle_drive_specification_command(FDCtrl *fdctrl, int direction)
+ {
+     FDrive *cur_drv = get_cur_drv(fdctrl);
++    uint32_t pos;
+ 
+-    if (fdctrl->fifo[fdctrl->data_pos - 1] & 0x80) {
++    pos = fdctrl->data_pos - 1;
++    pos %= FD_SECTOR_LEN;
++    if (fdctrl->fifo[pos] & 0x80) {
+         /* Command parameters done */
+-        if (fdctrl->fifo[fdctrl->data_pos - 1] & 0x40) {
++        if (fdctrl->fifo[pos] & 0x40) {
+             fdctrl->fifo[0] = fdctrl->fifo[1];
+             fdctrl->fifo[2] = 0;
+             fdctrl->fifo[3] = 0;
+@@ -1955,7 +1958,7 @@ static uint8_t command_to_handler[256];
+ static void fdctrl_write_data(FDCtrl *fdctrl, uint32_t value)
+ {
+     FDrive *cur_drv;
+-    int pos;
++    uint32_t pos;
+ 
+     /* Reset mode */
+     if (!(fdctrl->dor & FD_DOR_nRESET)) {
+@@ -2004,7 +2007,9 @@ static void fdctrl_write_data(FDCtrl *fdctrl, uint32_t value)
+     }
+ 
+     FLOPPY_DPRINTF("%s: %02x\n", __func__, value);
+-    fdctrl->fifo[fdctrl->data_pos++] = value;
++    pos = fdctrl->data_pos++;
++    pos %= FD_SECTOR_LEN;
++    fdctrl->fifo[pos] = value;
+     if (fdctrl->data_pos == fdctrl->data_len) {
+         /* We now have all parameters
+          * and will be able to treat the command
+-- 
+1.7.0.4
+

diff --git a/app-emulation/qemu/qemu-2.2.0-r99.ebuild b/app-emulation/qemu/qemu-2.2.1-r99.ebuild
similarity index 97%
rename from app-emulation/qemu/qemu-2.2.0-r99.ebuild
rename to app-emulation/qemu/qemu-2.2.1-r99.ebuild
index 8bdbc95..5b8baf1 100644
--- a/app-emulation/qemu/qemu-2.2.0-r99.ebuild
+++ b/app-emulation/qemu/qemu-2.2.1-r99.ebuild
@@ -1,10 +1,10 @@
 # Copyright 1999-2015 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
-# $Header: /var/cvsroot/gentoo-x86/app-emulation/qemu/qemu-2.2.0.ebuild,v 1.3 2015/03/12 10:06:51 ago Exp $
+# $Header: /var/cvsroot/gentoo-x86/app-emulation/qemu/qemu-2.2.1-r2.ebuild,v 1.3 2015/05/14 07:09:58 ago Exp $
 
 EAPI=5
 
-PYTHON_COMPAT=( python{2_6,2_7} )
+PYTHON_COMPAT=( python2_7 )
 PYTHON_REQ_USE="ncurses,readline"
 
 inherit eutils flag-o-matic linux-info toolchain-funcs multilib python-r1 \
@@ -20,9 +20,8 @@ if [[ ${PV} = *9999* ]]; then
 else
 	SRC_URI="http://wiki.qemu-project.org/download/${P}.tar.bz2
 	${BACKPORTS:+
-		http://dev.gentoo.org/~cardoe/distfiles/${P}-${BACKPORTS}.tar.xz
-		http://dev.gentoo.org/~tamiko/distfiles/${P}-${BACKPORTS}.tar.xz}"
-	KEYWORDS="amd64 ~ppc ~x86"
+		http://dev.gentoo.org/~cardoe/distfiles/${P}-${BACKPORTS}.tar.xz}"
+	KEYWORDS="amd64 ~ppc ~ppc64 x86 ~x86-fbsd"
 fi
 
 DESCRIPTION="QEMU + Kernel-based Virtual Machine userland tools"
@@ -77,13 +76,13 @@ SOFTMMU_LIB_DEPEND="${COMMON_LIB_DEPEND}
 	curl? ( >=net-misc/curl-7.15.4[static-libs(+)] )
 	fdt? ( >=sys-apps/dtc-1.4.0[static-libs(+)] )
 	glusterfs? ( >=sys-cluster/glusterfs-3.4.0[static-libs(+)] )
-	infiniband? ( sys-infiniband/librdmacm[static-libs(+)] )
-	jpeg? ( virtual/jpeg[static-libs(+)] )
+	infiniband? ( sys-infiniband/librdmacm:=[static-libs(+)] )
+	jpeg? ( virtual/jpeg:=[static-libs(+)] )
 	lzo? ( dev-libs/lzo:2[static-libs(+)] )
 	ncurses? ( sys-libs/ncurses[static-libs(+)] )
 	nfs? ( >=net-fs/libnfs-1.9.3[static-libs(+)] )
 	numa? ( sys-process/numactl[static-libs(+)] )
-	png? ( media-libs/libpng[static-libs(+)] )
+	png? ( media-libs/libpng:0=[static-libs(+)] )
 	rbd? ( sys-cluster/ceph[static-libs(+)] )
 	sasl? ( dev-libs/cyrus-sasl[static-libs(+)] )
 	sdl? ( >=media-libs/libsdl-1.2.11[static-libs(+)] )
@@ -246,6 +245,7 @@ pkg_pretend() {
 
 pkg_setup() {
 	enewgroup kvm 78
+	python_setup
 }
 
 src_prepare() {
@@ -258,6 +258,9 @@ src_prepare() {
 	use nls || rm -f po/*.po
 
 	epatch "${FILESDIR}"/qemu-1.7.0-cflags.patch
+	epatch "${FILESDIR}"/${P}-CVE-2015-1779-1.patch #544328
+	epatch "${FILESDIR}"/${P}-CVE-2015-1779-2.patch #544328
+	epatch "${FILESDIR}"/${PN}-2.3.0-CVE-2015-3456.patch #549404
 
 	# Patching for musl
 	epatch "${FILESDIR}"/${PN}-2.0.0-F_SHLCK-and-F_EXLCK.patch
@@ -399,7 +402,7 @@ qemu_src_configure() {
 		gcc-specs-pie && conf_opts+=( --enable-pie )
 	fi
 
-	einfo "./configure ${conf_opts[*]}"
+	einfo "../configure ${conf_opts[*]}"
 	cd "${builddir}"
 	../configure "${conf_opts[@]}" || die "configure failed"
 


             reply	other threads:[~2015-06-08 12:26 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-06-08 12:26 Anthony G. Basile [this message]
  -- strict thread matches above, loose matches on Subject: below --
2014-11-18 21:57 [gentoo-commits] proj/hardened-dev:musl commit in: app-emulation/qemu/files/, app-emulation/qemu/ Anthony G. Basile
2014-10-10 18:20 Anthony G. Basile

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=1433766459.dd8f541bb891cc198527837f2eedb81594efb1f3.blueness@gentoo \
    --to=blueness@gentoo.org \
    --cc=gentoo-commits@lists.gentoo.org \
    --cc=gentoo-dev@lists.gentoo.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