all messages for Guix-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
From: Leo Famulari <leo@famulari.name>
To: guix-devel@gnu.org
Subject: Re: libgd security update / i686 issues
Date: Thu, 28 Jul 2016 17:26:18 -0400	[thread overview]
Message-ID: <20160728212618.GA12938@jasmine> (raw)
In-Reply-To: <20160728072337.GA1011@jasmine>

[-- Attachment #1: Type: text/plain, Size: 262 bytes --]

On Thu, Jul 28, 2016 at 03:23:37AM -0400, Leo Famulari wrote:
> libgd 2.2.3 has been released [0], which includes fixes for
> CVE-2016-6207.

Instead of updating to 2.2.3, we could also try cherry-picking the
upstream commits that address this bug, as attached.

[-- Attachment #2: 0001-gnu-gd-Fix-CVE-2016-6207.patch --]
[-- Type: text/x-diff, Size: 16816 bytes --]

From 1ac0113094a8a2914f9f78da2d2e13c378c61e06 Mon Sep 17 00:00:00 2001
From: Leo Famulari <leo@famulari.name>
Date: Thu, 28 Jul 2016 17:23:53 -0400
Subject: [PATCH] gnu: gd: Fix CVE-2016-6207.

* gnu/packages/patches/gd-CVE-2016-6207.patch: New file.
* gnu/local.mk (dist_patch_DATA): Add it.
* gnu/packages/gd.scm (gd)[source]: Use it.
---
 gnu/local.mk                                |   1 +
 gnu/packages/gd.scm                         |   1 +
 gnu/packages/patches/gd-CVE-2016-6207.patch | 455 ++++++++++++++++++++++++++++
 3 files changed, 457 insertions(+)
 create mode 100644 gnu/packages/patches/gd-CVE-2016-6207.patch

diff --git a/gnu/local.mk b/gnu/local.mk
index c789b19..6b9b2c4 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -516,6 +516,7 @@ dist_patch_DATA =						\
   %D%/packages/patches/gd-CVE-2016-5766.patch			\
   %D%/packages/patches/gd-CVE-2016-6128.patch			\
   %D%/packages/patches/gd-CVE-2016-6132.patch			\
+  %D%/packages/patches/gd-CVE-2016-6207.patch			\
   %D%/packages/patches/gd-CVE-2016-6214.patch			\
   %D%/packages/patches/gd-fix-test-on-i686.patch		\
   %D%/packages/patches/gegl-CVE-2012-4433.patch			\
diff --git a/gnu/packages/gd.scm b/gnu/packages/gd.scm
index 3313ee6..83f0d48 100644
--- a/gnu/packages/gd.scm
+++ b/gnu/packages/gd.scm
@@ -51,6 +51,7 @@
                                       "gd-CVE-2016-5766.patch"
                                       "gd-CVE-2016-6128.patch"
                                       "gd-CVE-2016-6132.patch"
+                                      "gd-CVE-2016-6207.patch"
                                       "gd-CVE-2016-6214.patch"))
              (sha256
               (base32
diff --git a/gnu/packages/patches/gd-CVE-2016-6207.patch b/gnu/packages/patches/gd-CVE-2016-6207.patch
new file mode 100644
index 0000000..255cd20
--- /dev/null
+++ b/gnu/packages/patches/gd-CVE-2016-6207.patch
@@ -0,0 +1,455 @@
+Fix CVE-2016-6207 (denial of service caused by integer overflow in
+_gdContributionsAlloc()):
+
+<https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2015-8869>
+
+Copied from upstream commits:
+<https://github.com/libgd/libgd/commit/0dd40abd6d5b3e53a6b745dd4d6cf94b70010989>
+<https://github.com/libgd/libgd/commit/d325888a9fe3c9681e4a9aad576de2c5cd5df2ef>
+<https://github.com/libgd/libgd/commit/ff9113c80a32205d45205d3ea30965b25480e0fb>
+<https://github.com/libgd/libgd/commit/f60ec7a546499f9446063a4dbe755be9523d8232>
+<https://github.com/libgd/libgd/commit/7a28c235890c95e6010e7b0d0f7c7369367168ef>
+
+From 819ae1b7fce4a61a1492640dd08daa19066af5ab Mon Sep 17 00:00:00 2001
+From: Pierre Joye <pierre.php@gmail.com>
+Date: Tue, 19 Jul 2016 14:45:56 +0700
+Subject: [PATCH] fix possible OOB or OOM in gdImageScale, reported by Secunia
+ (CVE 2016-6207)
+
+---
+ src/gd.c                                         | 89 +++++++++++-------------
+ src/gd_interpolation.c                           | 47 +++++++++++--
+ tests/gdimagescale/CMakeLists.txt                |  1 +
+ tests/gdimagescale/Makemodule.am                 |  3 +-
+ tests/gdimagescale/bug_overflow_large_new_size.c | 31 +++++++++
+ 5 files changed, 116 insertions(+), 55 deletions(-)
+ create mode 100644 tests/gdimagescale/bug_overflow_large_new_size.c
+
+diff --git a/src/gd.c b/src/gd.c
+index 855e8ca..7faf066 100644
+--- a/src/gd.c
++++ b/src/gd.c
+@@ -272,7 +272,7 @@ BGD_DECLARE(gdImagePtr) gdImageCreateTrueColor (int sx, int sy)
+ 		return 0;
+ 	}
+ 
+-	if (overflow2(sizeof(int), sx)) {
++	if (overflow2(sizeof(int *), sx)) {
+ 		return NULL;
+ 	}
+ 
+@@ -2946,78 +2946,77 @@ BGD_DECLARE(void) gdImageCopyResampled (gdImagePtr dst,
+ 										int dstW, int dstH, int srcW, int srcH)
+ {
+ 	int x, y;
+-	double sy1, sy2, sx1, sx2;
+ 	if (!dst->trueColor) {
+-		gdImageCopyResized (dst, src, dstX, dstY, srcX, srcY, dstW, dstH,
+-		                    srcW, srcH);
++		gdImageCopyResized (dst, src, dstX, dstY, srcX, srcY, dstW, dstH, srcW, srcH);
+ 		return;
+ 	}
+ 	for (y = dstY; (y < dstY + dstH); y++) {
+-		sy1 = ((double) y - (double) dstY) * (double) srcH / (double) dstH;
+-		sy2 = ((double) (y + 1) - (double) dstY) * (double) srcH /
+-		      (double) dstH;
+ 		for (x = dstX; (x < dstX + dstW); x++) {
+-			double sx, sy;
+-			double spixels = 0;
+-			double red = 0.0, green = 0.0, blue = 0.0, alpha = 0.0;
+-			double alpha_sum = 0.0, contrib_sum = 0.0;
+-
+-			sx1 = ((double) x - (double) dstX) * (double) srcW / dstW;
+-			sx2 = ((double) (x + 1) - (double) dstX) * (double) srcW / dstW;
++			float sy1, sy2, sx1, sx2;
++			float sx, sy;
++			float spixels = 0.0;
++			float red = 0.0, green = 0.0, blue = 0.0, alpha = 0.0;
++			float alpha_factor, alpha_sum = 0.0, contrib_sum = 0.0;
++			sy1 = ((float)(y - dstY)) * (float)srcH / (float)dstH;
++			sy2 = ((float)(y + 1 - dstY)) * (float) srcH / (float) dstH;
+ 			sy = sy1;
+ 			do {
+-				double yportion;
+-				if (floor2 (sy) == floor2 (sy1)) {
+-					yportion = 1.0 - (sy - floor2 (sy));
++				float yportion;
++				if (floorf(sy) == floorf(sy1)) {
++					yportion = 1.0 - (sy - floorf(sy));
+ 					if (yportion > sy2 - sy1) {
+ 						yportion = sy2 - sy1;
+ 					}
+-					sy = floor2 (sy);
+-				} else if (sy == floor2 (sy2)) {
+-					yportion = sy2 - floor2 (sy2);
++					sy = floorf(sy);
++				} else if (sy == floorf(sy2)) {
++					yportion = sy2 - floorf(sy2);
+ 				} else {
+ 					yportion = 1.0;
+ 				}
++				sx1 = ((float)(x - dstX)) * (float) srcW / dstW;
++				sx2 = ((float)(x + 1 - dstX)) * (float) srcW / dstW;
+ 				sx = sx1;
+ 				do {
+-					double xportion;
+-					double pcontribution;
++					float xportion;
++					float pcontribution;
+ 					int p;
+-					if (floor2 (sx) == floor2 (sx1)) {
+-						xportion = 1.0 - (sx - floor2 (sx));
++					if (floorf(sx) == floorf(sx1)) {
++						xportion = 1.0 - (sx - floorf(sx));
+ 						if (xportion > sx2 - sx1) {
+ 							xportion = sx2 - sx1;
+ 						}
+-						sx = floor2 (sx);
+-					} else if (sx == floor2 (sx2)) {
+-						xportion = sx2 - floor2 (sx2);
++						sx = floorf(sx);
++					} else if (sx == floorf(sx2)) {
++						xportion = sx2 - floorf(sx2);
+ 					} else {
+ 						xportion = 1.0;
+ 					}
+ 					pcontribution = xportion * yportion;
+-					/* 2.08: previously srcX and srcY were ignored.
+-					   Andrew Pattison */
+-					p = gdImageGetTrueColorPixel (src,
+-					                              (int) sx + srcX,
+-					                              (int) sy + srcY);
+-					red += gdTrueColorGetRed (p) * pcontribution;
+-					green += gdTrueColorGetGreen (p) * pcontribution;
+-					blue += gdTrueColorGetBlue (p) * pcontribution;
++					p = gdImageGetTrueColorPixel(src, (int) sx + srcX, (int) sy + srcY);
++
++					alpha_factor = ((gdAlphaMax - gdTrueColorGetAlpha(p))) * pcontribution;
++					red += gdTrueColorGetRed (p) * alpha_factor;
++					green += gdTrueColorGetGreen (p) * alpha_factor;
++					blue += gdTrueColorGetBlue (p) * alpha_factor;
+ 					alpha += gdTrueColorGetAlpha (p) * pcontribution;
++					alpha_sum += alpha_factor;
++					contrib_sum += pcontribution;
+ 					spixels += xportion * yportion;
+ 					sx += 1.0;
+-				} while (sx < sx2);
+-				sy += 1.0;
+-			} while (sy < sy2);
++				}
++				while (sx < sx2);
++				sy += 1.0f;
++			}
++			while (sy < sy2);
++
+ 			if (spixels != 0.0) {
+ 				red /= spixels;
+ 				green /= spixels;
+ 				blue /= spixels;
+ 				alpha /= spixels;
+-				alpha += 0.5;
+ 			}
+-			if ( alpha_sum != 0.0f) {
+-				if( contrib_sum != 0.0f) {
++			if ( alpha_sum != 0.0) {
++				if( contrib_sum != 0.0) {
+ 					alpha_sum /= contrib_sum;
+ 				}
+ 				red /= alpha_sum;
+@@ -3031,17 +3030,13 @@ BGD_DECLARE(void) gdImageCopyResampled (gdImagePtr dst,
+ 			if (green > 255.0) {
+ 				green = 255.0;
+ 			}
+-			if (blue > 255.0) {
++			if (blue > 255.0f) {
+ 				blue = 255.0;
+ 			}
+ 			if (alpha > gdAlphaMax) {
+ 				alpha = gdAlphaMax;
+ 			}
+-			gdImageSetPixel (dst,
+-			                 x, y,
+-			                 gdTrueColorAlpha ((int) red,
+-			                                   (int) green,
+-			                                   (int) blue, (int) alpha));
++			gdImageSetPixel(dst, x, y, gdTrueColorAlpha ((int) red, (int) green, (int) blue, (int) alpha));
+ 		}
+ 	}
+ }
+diff --git a/src/gd_interpolation.c b/src/gd_interpolation.c
+index da6c8ad..72845d2 100644
+--- a/src/gd_interpolation.c
++++ b/src/gd_interpolation.c
+@@ -829,6 +829,7 @@ static inline LineContribType * _gdContributionsAlloc(unsigned int line_length,
+ {
+ 	unsigned int u = 0;
+ 	LineContribType *res;
++	int overflow_error = 0;
+ 
+ 	res = (LineContribType *) gdMalloc(sizeof(LineContribType));
+ 	if (!res) {
+@@ -836,10 +837,28 @@ static inline LineContribType * _gdContributionsAlloc(unsigned int line_length,
+ 	}
+ 	res->WindowSize = windows_size;
+ 	res->LineLength = line_length;
++	if (overflow2(line_length, sizeof(ContributionType))) {
++		return NULL;
++	}
+ 	res->ContribRow = (ContributionType *) gdMalloc(line_length * sizeof(ContributionType));
+-
++	if (res->ContribRow == NULL) {
++		gdFree(res);
++		return NULL;
++	}
+ 	for (u = 0 ; u < line_length ; u++) {
+-		res->ContribRow[u].Weights = (double *) gdMalloc(windows_size * sizeof(double));
++		if (overflow2(windows_size, sizeof(double))) {
++			overflow_error = 1;
++		} else {
++			res->ContribRow[u].Weights = (double *) gdMalloc(windows_size * sizeof(double));
++		}
++		if (overflow_error == 1 || res->ContribRow[u].Weights == NULL) {
++			u--;
++			while (u >= 0) {
++				gdFree(res->ContribRow[u].Weights);
++				u--;
++			}
++			return NULL;
++		}
+ 	}
+ 	return res;
+ }
+@@ -872,7 +891,9 @@ static inline LineContribType *_gdContributionsCalc(unsigned int line_size, unsi
+ 
+ 	windows_size = 2 * (int)ceil(width_d) + 1;
+ 	res = _gdContributionsAlloc(line_size, windows_size);
+-
++	if (res == NULL) {
++		return NULL;
++	}
+ 	for (u = 0; u < line_size; u++) {
+ 		const double dCenter = (double)u / scale_d;
+ 		/* get the significant edge points affecting the pixel */
+@@ -977,7 +998,6 @@ _gdScalePass(const gdImagePtr pSrc, const unsigned int src_len,
+         _gdScaleOneAxis(pSrc, pDst, dst_len, line_ndx, contrib, axis);
+ 	}
+ 	_gdContributionsFree (contrib);
+-
+     return 1;
+ }/* _gdScalePass*/
+ 
+@@ -990,6 +1010,7 @@ gdImageScaleTwoPass(const gdImagePtr src, const unsigned int new_width,
+     const unsigned int src_height = src->sy;
+ 	gdImagePtr tmp_im = NULL;
+ 	gdImagePtr dst = NULL;
++	int scale_pass_res;
+ 
+     /* First, handle the trivial case. */
+     if (src_width == new_width && src_height == new_height) {
+@@ -1011,7 +1032,11 @@ gdImageScaleTwoPass(const gdImagePtr src, const unsigned int new_width,
+         }
+         gdImageSetInterpolationMethod(tmp_im, src->interpolation_id);
+ 
+-        _gdScalePass(src, src_width, tmp_im, new_width, src_height, HORIZONTAL);
++		scale_pass_res = _gdScalePass(src, src_width, tmp_im, new_width, src_height, HORIZONTAL);
++		if (scale_pass_res != 1) {
++			gdImageDestroy(tmp_im);
++			return NULL;
++		}
+     }/* if .. else*/
+ 
+     /* If vertical sizes match, we're done. */
+@@ -1024,10 +1049,18 @@ gdImageScaleTwoPass(const gdImagePtr src, const unsigned int new_width,
+ 	dst = gdImageCreateTrueColor(new_width, new_height);
+ 	if (dst != NULL) {
+         gdImageSetInterpolationMethod(dst, src->interpolation_id);
+-        _gdScalePass(tmp_im, src_height, dst, new_height, new_width, VERTICAL);
++        scale_pass_res = _gdScalePass(tmp_im, src_height, dst, new_height, new_width, VERTICAL);
++		if (scale_pass_res != 1) {
++			gdImageDestroy(dst);
++			if (src != tmp_im && tmp_im != NULL) {
++				gdImageDestroy(tmp_im);
++			}
++			return NULL;
++	   }
+     }/* if */
+ 
+-    if (src != tmp_im) {
++
++	if (src != tmp_im && tmp_im != NULL) {
+         gdImageDestroy(tmp_im);
+     }/* if */
+ 
+diff --git a/tests/gdimagescale/CMakeLists.txt b/tests/gdimagescale/CMakeLists.txt
+index 1098e06..91bd015 100644
+--- a/tests/gdimagescale/CMakeLists.txt
++++ b/tests/gdimagescale/CMakeLists.txt
+@@ -1,5 +1,6 @@
+ SET(TESTS_FILES
+ 	github_bug_00218
++	bug_overflow_large_new_size
+ )
+ 
+ ADD_GD_TESTS()
+diff --git a/tests/gdimagescale/Makemodule.am b/tests/gdimagescale/Makemodule.am
+index dacabe7..23b8924 100644
+--- a/tests/gdimagescale/Makemodule.am
++++ b/tests/gdimagescale/Makemodule.am
+@@ -1,6 +1,7 @@
+ 
+ libgd_test_programs += \
+-	gdimagescale/github_bug_00218
++	gdimagescale/github_bug_00218 \
++	gdimagescale/bug_overflow_large_new_size
+ 
+ EXTRA_DIST += \
+ 	gdimagescale/CMakeLists.txt
+diff --git a/tests/gdimagescale/bug_overflow_large_new_size.c b/tests/gdimagescale/bug_overflow_large_new_size.c
+new file mode 100644
+index 0000000..0a8503b
+--- /dev/null
++++ b/tests/gdimagescale/bug_overflow_large_new_size.c
+@@ -0,0 +1,31 @@
++#include <stdio.h>
++#include <stdlib.h>
++#include "gd.h"
++#include <math.h>
++
++#include "gdtest.h"
++
++int main()
++{
++	gdImagePtr im, im2;
++
++	im = gdImageCreate(1,1);
++	if (im == NULL) {
++		printf("gdImageCreate failed\n");
++		return 1;
++	}
++	gdImageSetInterpolationMethod(im, GD_BELL);
++	
++	/* here the call may pass if the system has enough memory (physical or swap)
++	   or fails (overflow check or alloc fails.
++	   in both cases the tests pass */
++	im2 = gdImageScale(im,0x15555556, 1);
++	if (im2 == NULL) {
++		printf("gdImageScale failed, expected (out of memory or overflow validation\n");
++		return 0;
++	}
++	gdImageDestroy(im);
++	gdImageDestroy(im2);
++
++	return 0;
++}
+-- 
+2.9.2
+
+From d325888a9fe3c9681e4a9aad576de2c5cd5df2ef Mon Sep 17 00:00:00 2001
+From: Pierre Joye <pierre.php@gmail.com>
+Date: Tue, 19 Jul 2016 15:25:47 +0700
+Subject: [PATCH 1/3] fix possible OOB or OOM in gdImageScale, reported by
+ Secunia (CVE 2016-6207)
+
+---
+ src/gd_interpolation.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/src/gd_interpolation.c b/src/gd_interpolation.c
+index 6b7e4ec..602d0f7 100644
+--- a/src/gd_interpolation.c
++++ b/src/gd_interpolation.c
+@@ -838,6 +838,7 @@ static inline LineContribType * _gdContributionsAlloc(unsigned int line_length,
+ 	res->WindowSize = windows_size;
+ 	res->LineLength = line_length;
+ 	if (overflow2(line_length, sizeof(ContributionType))) {
++		gdFree(res);
+ 		return NULL;
+ 	}
+ 	res->ContribRow = (ContributionType *) gdMalloc(line_length * sizeof(ContributionType));
+-- 
+2.9.2
+
+From ff9113c80a32205d45205d3ea30965b25480e0fb Mon Sep 17 00:00:00 2001
+From: Pierre Joye <pierre.php@gmail.com>
+Date: Tue, 19 Jul 2016 15:57:08 +0700
+Subject: [PATCH 2/3] fix possible OOB or OOM in gdImageScale, reported by
+ Secunia (CVE 2016-6207)
+
+---
+ src/gd_interpolation.c | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/src/gd_interpolation.c b/src/gd_interpolation.c
+index 602d0f7..ca1ad10 100644
+--- a/src/gd_interpolation.c
++++ b/src/gd_interpolation.c
+@@ -853,11 +853,12 @@ static inline LineContribType * _gdContributionsAlloc(unsigned int line_length,
+ 			res->ContribRow[u].Weights = (double *) gdMalloc(windows_size * sizeof(double));
+ 		}
+ 		if (overflow_error == 1 || res->ContribRow[u].Weights == NULL) {
++			unsigned int i;
+ 			u--;
+-			while (u >= 0) {
+-				gdFree(res->ContribRow[u].Weights);
+-				u--;
++			for (i=0;i<=u;i++) {
++				gdFree(res->ContribRow[i].Weights);
+ 			}
++			gdFree(res);
+ 			return NULL;
+ 		}
+ 	}
+-- 
+2.9.2
+
+From f60ec7a546499f9446063a4dbe755be9523d8232 Mon Sep 17 00:00:00 2001
+From: Pierre Joye <pierre.php@gmail.com>
+Date: Tue, 19 Jul 2016 16:30:52 +0700
+Subject: [PATCH 3/3] fix possible OOB or OOM in gdImageScale, reported by
+ Secunia (CVE 2016-6207)
+
+---
+ src/gd_interpolation.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/src/gd_interpolation.c b/src/gd_interpolation.c
+index ca1ad10..c9bcb0c 100644
+--- a/src/gd_interpolation.c
++++ b/src/gd_interpolation.c
+@@ -858,6 +858,7 @@ static inline LineContribType * _gdContributionsAlloc(unsigned int line_length,
+ 			for (i=0;i<=u;i++) {
+ 				gdFree(res->ContribRow[i].Weights);
+ 			}
++			gdFree(res->ContribRow);
+ 			gdFree(res);
+ 			return NULL;
+ 		}
+-- 
+2.9.2
+
+From c64a4aeeeeed7b81bc732ca993224ece9ebbc126 Mon Sep 17 00:00:00 2001
+From: Pierre Joye <pierre.php@gmail.com>
+Date: Tue, 19 Jul 2016 17:05:54 +0700
+Subject: [PATCH] fix possible OOB or OOM in gdImageScale, reported by Secunia
+ (CVE 2016-6207)
+
+---
+ src/gd_interpolation.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/gd_interpolation.c b/src/gd_interpolation.c
+index c9bcb0c..3f4b49f 100644
+--- a/src/gd_interpolation.c
++++ b/src/gd_interpolation.c
+@@ -1063,7 +1063,7 @@ gdImageScaleTwoPass(const gdImagePtr src, const unsigned int new_width,
+     }/* if */
+ 
+ 
+-	if (src != tmp_im && tmp_im != NULL) {
++	if (tmp_im != NULL && src != tmp_im) {
+         gdImageDestroy(tmp_im);
+     }/* if */
+ 
+-- 
+2.9.2
+
-- 
2.9.2


  parent reply	other threads:[~2016-07-28 21:26 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-07-28  7:23 libgd security update / i686 issues Leo Famulari
2016-07-28  8:34 ` Andreas Enge
2016-07-28  8:40 ` Andreas Enge
2016-07-28 16:30   ` Leo Famulari
2016-07-28 17:22     ` Mark H Weaver
2016-07-28 18:38       ` Leo Famulari
2016-07-28 18:56       ` Leo Famulari
2016-07-28 20:47         ` Leo Famulari
2016-07-29 17:59         ` Mark H Weaver
2016-07-29 18:52           ` Leo Famulari
2016-07-29 20:33           ` Mark H Weaver
2016-07-28 21:26 ` Leo Famulari [this message]
2016-07-29 15:00   ` Ludovic Courtès
2016-07-29 15:42     ` Leo Famulari

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=20160728212618.GA12938@jasmine \
    --to=leo@famulari.name \
    --cc=guix-devel@gnu.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.
Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/guix.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.