From: Ricardo Neri <ricardo.neri-calderon@linux.intel.com>
To: Borislav Petkov <bp@suse.de>
Cc: Ingo Molnar <mingo@redhat.com>,
Thomas Gleixner <tglx@linutronix.de>,
"H. Peter Anvin" <hpa@zytor.com>,
Andy Lutomirski <luto@kernel.org>,
Peter Zijlstra <peterz@infradead.org>,
Andrew Morton <akpm@linux-foundation.org>,
Brian Gerst <brgerst@gmail.com>,
Chris Metcalf <cmetcalf@mellanox.com>,
Dave Hansen <dave.hansen@linux.intel.com>,
Paolo Bonzini <pbonzini@redhat.com>,
Masami Hiramatsu <mhiramat@kernel.org>,
Huang Rui <ray.huang@amd.com>, Jiri Slaby <jslaby@suse.cz>,
Jonathan Corbet <corbet@lwn.net>,
"Michael S. Tsirkin" <mst@redhat.com>,
Paul Gortmaker <paul.gortmaker@windriver.com>,
Vlastimil Babka <vbabka@suse.cz>, Chen Yucong <slaoub@gmail.com>,
"Ravi V. Shankar" <ravi.v.shankar@intel.com>,
Shuah Khan <shuah@kernel.org>,
linux-kernel@vger.kernel.org, x86@kernel.org,
Adam Buchbinder <adam.buchbinder@gmail.com>,
Colin Ian King <colin.king@canonical.com>,
Lorenzo Stoakes <lstoakes@gmail.com>,
Qiaowei Ren <qiaowei.ren@intel.com>,
Arnaldo Carvalho de Melo <acme@redhat.com>,
Adrian Hunter <adrian.hunter@intel.com>,
Kees Cook <keescook@chromium.org>,
Thomas Garnier <thgarnie@google.com>,
Dmitry Vyukov <dvyukov@google.com>
Subject: Re: [PATCH v8 12/28] x86/insn-eval: Add utility functions to get segment selector
Date: Tue, 26 Sep 2017 21:21:44 -0700 [thread overview]
Message-ID: <1506486104.8286.142.camel@linux.intel.com> (raw)
In-Reply-To: <20170926104353.vmpxybv3v5immc56@pd.tnic>
On Tue, 2017-09-26 at 12:43 +0200, Borislav Petkov wrote:
> Hi,
>
> On Fri, Aug 18, 2017 at 05:27:53PM -0700, Ricardo Neri wrote:
> >
> > When computing a linear address and segmentation is used, we need
> > to know
> > the base address of the segment involved in the computation. In
> > most of
> > the cases, the segment base address will be zero as in
> > USER_DS/USER32_DS.
> ...
>
> >
> > arch/x86/include/asm/inat.h | 10 ++
> > arch/x86/lib/insn-eval.c | 278
> > ++++++++++++++++++++++++++++++++++++++++++++
> > 2 files changed, 288 insertions(+)
> so I did a bunch of simplifications on top, see if you agree:
>
> * we should always test for if (!insn) first because otherwise we
> can't talk
> about a segment at all.
This is true except when we don't have an insn at all (well, it may be
non-NULL but it will only contain garbage). The case to which I am
referring is when we begin decoding our instruction. The first step is
to copy_from_user the instruction and populate insn. For this we must
calculate the linear address from where we copy using CS and rIP.
Furthermore, in this only case we don't need to look at insn at all as
the only register involved is rIP no segment override prefixes are
allowed.
Please see my comment below.
>
> * the nomenclature should be clear: if we return INAT_SEG_REG_* those
> are own
> defined indices and not registers or prefixes or whatever else, so
> everywhere we
> state that we're returning an *index*.
I agree.
>
> * and then shorten local variables' names as reading "reg" every
> other line doesn't make it clearer :)
I agree.
>
> * also some comments formatting for better readability.
Thanks!
>
> * and prefixing register names with "r" in the comments means then
> all
> register widths, not only 32-bit. Dunno, is "(E)" SDM nomenclature
> for
> the different register widths?
A quick look at the section 3.1.1.3 of the Intel Software Development
Manual Vol2 reveals that r/m16 operands are referred as [ACDB]X,
[SB]P,and [SD]I. r/m32 operands are referred as E[ACDB]X, E[SB]P and
E[SD]I. r/m64 operands are referred as R[ACDB]X, R[SB]P, R[SD]I and
R[8-15].
Also, some instructions (e.g., string structions) do use the
nomenclature (E)[DI]I protected mode and (R|E)[DI]I for long mode.
I only used "(E)" (i.e., not the "(R|)" part) as these utility
functions will deal mostly with protected mode, unless FS or GS are
used in long mode.
>
> ---
> diff --git a/arch/x86/lib/insn-eval.c b/arch/x86/lib/insn-eval.c
> index 86f58ce6c302..720529573d72 100644
> --- a/arch/x86/lib/insn-eval.c
> +++ b/arch/x86/lib/insn-eval.c
> @@ -44,50 +44,45 @@ static bool is_string_insn(struct insn *insn)
> }
>
> /**
> - * get_overridden_seg_reg() - obtain segment register to use from
> prefixes
> - * @insn: Instruction structure with segment override
> prefixes
> - * @regs: Structure with register values as seen when
> entering kernel mode
> + * get_seg_reg_idx() - obtain segment register index to use from
> prefixes
> + * @insn: Instruction with segment override prefixes
> + * @regs: Register values as seen when entering kernel mode
> * @regoff: Operand offset, in pt_regs, used to deterimine
> segment register
> *
> - * The segment register to which an effective address refers depends
> on
> - * a) whether running in long mode (in such a case semgment override
> prefixes
> - * are ignored. b) Whether segment override prefixes must be ignored
> for certain
> - * registers: always use CS when the register is (R|E)IP; always use
> ES when
> - * operand register is (E)DI with a string instruction as defined in
> the Intel
> - * documentation. c) If segment overrides prefixes are found in the
> instruction
> - * prefixes. d) Use the default segment register associated with the
> operand
> - * register.
> + * The segment register to which an effective address refers,
> depends on:
> + *
> + * a) whether running in long mode (in such a case segment override
> prefixes
> + * are ignored).
> + *
> + * b) Whether segment override prefixes must be ignored for certain
> + * registers: always use CS when the register is rIP; always use ES
> when
> + * operand register is rDI with a string instruction as defined in
> the Intel
> + * documentation.
> *
> - * This function returns the overridden segment register to use, if
> any, as per
> - * the conditions described above. Please note that this function
> + * c) If segment overrides prefixes are found in the instruction
> prefixes.
> + *
> + * d) Use the default segment register associated with the operand
> register.
> + *
> + * This function returns the segment register override to use, if
> any,
> + * as per the conditions described above. Please note that this
> function
> * does not return the value in the segment register (i.e., the
> segment
> - * selector). The segment selector needs to be obtained using
> - * get_segment_selector() and passing the segment register resolved
> by
> + * selector) but our defined index. The segment selector needs to be
> obtained
> + * using get_segment_selector() and passing the segment register
> resolved by
> * this function.
> *
> - * Return: A constant identifying the segment register to use, among
> CS, SS, DS,
> + * Returns:
> + *
> + * A constant identifying the segment register to use, among CS, SS,
> DS,
> * ES, FS, or GS. INAT_SEG_REG_IGNORE is returned if running in long
> mode.
> * INAT_SEG_REG_DEFAULT is returned if no segment override prefixes
> were found
> - * and the default segment register shall be used. -EINVAL in case
> of error.
> + * and the default segment register shall be used.
> + *
> + * -EINVAL in case of error.
> */
This rewording looks OK to me. Thanks!
> -static int get_overridden_seg_reg(struct insn *insn, struct pt_regs
> *regs,
> - int regoff)
> +static int get_seg_reg_idx(struct insn *insn, struct pt_regs *regs,
> int regoff)
> {
> - int i;
> - int sel_overrides = 0;
> - int seg_register = INAT_SEG_REG_DEFAULT;
> -
> - /*
> - * Segment override prefixes should not be used for (E)IP.
> Check this
> - * case first as we might not have (and not needed at all) a
> - * valid insn structure to evaluate segment override
> prefixes.
> - */
> - if (regoff == offsetof(struct pt_regs, ip)) {
> - if (user_64bit_mode(regs))
> - return INAT_SEG_REG_IGNORE;
> - else
> - return INAT_SEG_REG_DEFAULT;
> - }
This function essentially inspects insn to find segment override
prefixes. However, if called with rIP, we still don't have any
instruction to inspect (we are yet to copy_from_user it). insn would
essentially contain garbage. I guess callers could zero-init insn in
such a case. However, I think that keeping this check makes things more
clear.
> + int idx = INAT_SEG_REG_DEFAULT;
> + int sel_overrides = 0, i;
>
> if (!insn)
> return -EINVAL;
> @@ -101,27 +96,27 @@ static int get_overridden_seg_reg(struct insn
> *insn, struct pt_regs *regs,
> attr = inat_get_opcode_attribute(insn-
> >prefixes.bytes[i]);
> switch (attr) {
> case INAT_MAKE_PREFIX(INAT_PFX_CS):
> - seg_register = INAT_SEG_REG_CS;
> + idx = INAT_SEG_REG_CS;
> sel_overrides++;
> break;
> case INAT_MAKE_PREFIX(INAT_PFX_SS):
> - seg_register = INAT_SEG_REG_SS;
> + idx = INAT_SEG_REG_SS;
> sel_overrides++;
> break;
> case INAT_MAKE_PREFIX(INAT_PFX_DS):
> - seg_register = INAT_SEG_REG_DS;
> + idx = INAT_SEG_REG_DS;
> sel_overrides++;
> break;
> case INAT_MAKE_PREFIX(INAT_PFX_ES):
> - seg_register = INAT_SEG_REG_ES;
> + idx = INAT_SEG_REG_ES;
> sel_overrides++;
> break;
> case INAT_MAKE_PREFIX(INAT_PFX_FS):
> - seg_register = INAT_SEG_REG_FS;
> + idx = INAT_SEG_REG_FS;
> sel_overrides++;
> break;
> case INAT_MAKE_PREFIX(INAT_PFX_GS):
> - seg_register = INAT_SEG_REG_GS;
> + idx = INAT_SEG_REG_GS;
> sel_overrides++;
> break;
> /* No default action needed. */
> @@ -133,26 +128,26 @@ static int get_overridden_seg_reg(struct insn
> *insn, struct pt_regs *regs,
> * overrides for FS and GS.
> */
> if (user_64bit_mode(regs)) {
> - if (seg_register != INAT_SEG_REG_FS &&
> - seg_register != INAT_SEG_REG_GS)
> + if (idx != INAT_SEG_REG_FS &&
> + idx != INAT_SEG_REG_GS)
> return INAT_SEG_REG_IGNORE;
> /* More than one segment override prefix leads to undefined
> behavior. */
> } else if (sel_overrides > 1) {
> return -EINVAL;
> /*
> * Segment override prefixes are always ignored for string
> instructions
> - * that involve the use the (E)DI register.
> + * that use the (E)DI register.
> */
> } else if ((regoff == offsetof(struct pt_regs, di)) &&
> is_string_insn(insn)) {
> return INAT_SEG_REG_DEFAULT;
> }
>
> - return seg_register;
I will change to use indexes as you suggested.
> + return idx;
> }
>
> /**
> - * resolve_seg_register() - obtain segment register
> + * resolve_seg_reg() - obtain segment register index
> * @insn: Instruction structure with segment override
> prefixes
> * @regs: Structure with register values as seen when
> entering kernel mode
> * @regoff: Operand offset, in pt_regs, used to deterimine
> segment register
> @@ -169,36 +164,38 @@ static int get_overridden_seg_reg(struct insn
> *insn, struct pt_regs *regs,
> *
> * Return: A constant identifying the segment register to use, among
> CS, SS, DS,
> * ES, FS, or GS. INAT_SEG_REG_IGNORE is returned if running in long
> mode.
> + *
> * -EINVAL in case of error.
> */
> -static int resolve_seg_register(struct insn *insn, struct pt_regs
> *regs,
> - int regoff)
> +static int resolve_seg_reg(struct insn *insn, struct pt_regs *regs,
> int regoff)
> {
> - int seg_reg;
> + int idx;
>
> - seg_reg = get_overridden_seg_reg(insn, regs, regoff);
> + if (!insn)
> + return -EINVAL;
I checked for a NULL insn only after get_overriden_seg_reg (now
get_seg_reg_idx) because such function is able to handle a null insn.
However, this function not always needs a non-NULL insn. If obtaing the
regment register for rIP, there is not need to inspect the instruction
at all.
I only check for a NULL insn when needed (i.e., the contents of the
instruction could change the used segment register).
>
> - if (seg_reg < 0)
> - return seg_reg;
> + idx = get_seg_reg_idx(insn, regs, regoff);
> + if (idx < 0)
> + return idx;
>
> - if (seg_reg == INAT_SEG_REG_IGNORE)
> - return seg_reg;
> + if (idx == INAT_SEG_REG_IGNORE)
> + return idx;
>
> - if (seg_reg != INAT_SEG_REG_DEFAULT)
> - return seg_reg;
> + if (idx != INAT_SEG_REG_DEFAULT)
> + return idx;
>
> /*
> * If we are here, we use the default segment register as
> described
> * in the Intel documentation:
> - * + DS for all references involving (E)AX, (E)CX, (E)DX,
> (E)BX, and
> - * (E)SI.
> - * + If used in a string instruction, ES for (E)DI.
> Otherwise, DS.
> + *
> + * + DS for all references involving r[ABCD]X, and rSI.
> + * + If used in a string instruction, ES for rDI.
> Otherwise, DS.
> * + AX, CX and DX are not valid register operands in 16-
> bit address
> * encodings but are valid for 32-bit and 64-bit
> encodings.
> * + -EDOM is reserved to identify for cases in which no
> register
> * is used (i.e., displacement-only addressing). Use DS.
> - * + SS for (E)SP or (E)BP.
> - * + CS for (E)IP.
> + * + SS for rSP or rBP.
> + * + CS for rIP.
> */
Thanks for the rewording!
>
> switch (regoff) {
> @@ -206,24 +203,26 @@ static int resolve_seg_register(struct insn
> *insn, struct pt_regs *regs,
> case offsetof(struct pt_regs, cx):
> case offsetof(struct pt_regs, dx):
> /* Need insn to verify address size. */
> - if (!insn || insn->addr_bytes == 2)
> + if (insn->addr_bytes == 2)
Here we care if insn is NULL as we need to look at the address size.
> return -EINVAL;
> +
> case -EDOM:
> case offsetof(struct pt_regs, bx):
> case offsetof(struct pt_regs, si):
> return INAT_SEG_REG_DS;
> +
> case offsetof(struct pt_regs, di):
> - /* Need insn to see if insn is string instruction.
> */
> - if (!insn)
> - return -EINVAL;
Here we need a valid insn to determine if it contains a string
instruction.
> if (is_string_insn(insn))
> return INAT_SEG_REG_ES;
> return INAT_SEG_REG_DS;
> +
> case offsetof(struct pt_regs, bp):
> case offsetof(struct pt_regs, sp):
> return INAT_SEG_REG_SS;
> +
> case offsetof(struct pt_regs, ip):
> return INAT_SEG_REG_CS;
For CS we don't need insn at all.
> +
> default:
> return -EINVAL;
> }
> @@ -232,17 +231,20 @@ static int resolve_seg_register(struct insn
> *insn, struct pt_regs *regs,
> /**
> * get_segment_selector() - obtain segment selector
> * @regs: Structure with register values as seen when
> entering kernel mode
> - * @seg_reg: Segment register to use
> + * @seg_reg: Segment register index to use
> *
> - * Obtain the segment selector from any of the CS, SS, DS, ES, FS,
> GS segment
> - * registers. In CONFIG_X86_32, the segment is obtained from either
> pt_regs or
> - * kernel_vm86_regs as applicable. In CONFIG_X86_64, CS and SS are
> obtained
> + * Obtain the segment selector from any of the CS, SS, DS, ES, FS,
> GS
> + * segment registers. In CONFIG_X86_32, the segment is obtained from
> either
> + * pt_regs or kernel_vm86_regs as applicable. On 64-bit, CS and SS
> are obtained
> * from pt_regs. DS, ES, FS and GS are obtained by reading the
> actual CPU
> - * registers. This done for only for completeness as in
> CONFIG_X86_64 segment
> - * registers are ignored.
> + * registers. This done only for completeness as in long mode
> segment registers
> + * are ignored.
> + *
> + * Returns:
> + *
> + * Value of the segment selector, including null when running in
> long mode.
> *
> - * Return: Value of the segment selector, including null when
> running in
> - * long mode. -1 on error.
> + * -EINVAL on error.
Thanks for the rewording. I will incorporate it in the series.
Thanks and BR,
Ricardo
next prev parent reply other threads:[~2017-09-27 4:22 UTC|newest]
Thread overview: 67+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-08-19 0:27 [PATCH v8 00/28] x86: Enable User-Mode Instruction Prevention Ricardo Neri
2017-08-19 0:27 ` [PATCH v8 01/28] x86/mm: Relocate page fault error codes to traps.h Ricardo Neri
2017-08-19 0:27 ` [PATCH v8 02/28] x86/boot: Relocate definition of the initial state of CR0 Ricardo Neri
2017-08-19 0:27 ` Ricardo Neri
2017-08-19 0:27 ` Ricardo Neri
2017-08-25 17:41 ` Borislav Petkov
2017-08-25 17:41 ` Borislav Petkov
2017-08-25 17:41 ` Borislav Petkov
2017-08-31 4:04 ` Ricardo Neri
2017-08-31 4:04 ` Ricardo Neri
2017-08-31 4:04 ` Ricardo Neri
2017-08-31 9:51 ` Borislav Petkov
2017-08-31 9:51 ` Borislav Petkov
2017-08-31 9:51 ` Borislav Petkov
2017-09-02 17:35 ` Ricardo Neri
2017-09-02 17:35 ` Ricardo Neri
2017-09-02 17:35 ` Ricardo Neri
2017-08-19 0:27 ` [PATCH v8 03/28] ptrace,x86: Make user_64bit_mode() available to 32-bit builds Ricardo Neri
2017-08-19 0:27 ` [PATCH v8 04/28] uprobes/x86: Use existing definitions for segment override prefixes Ricardo Neri
2017-08-19 0:27 ` [PATCH v8 05/28] x86/mpx: Use signed variables to compute effective addresses Ricardo Neri
2017-08-29 16:09 ` Borislav Petkov
2017-08-31 4:19 ` Ricardo Neri
2017-08-31 9:52 ` Borislav Petkov
2017-08-19 0:27 ` [PATCH v8 06/28] x86/mpx: Do not use SIB.index if its value is 100b and ModRM.mod is not 11b Ricardo Neri
2017-08-31 19:38 ` Borislav Petkov
2017-09-02 17:19 ` Ricardo Neri
2017-08-19 0:27 ` [PATCH v8 07/28] x86/mpx: Do not use SIB.base if its value is 101b and ModRM.mod = 0 Ricardo Neri
2017-09-06 15:44 ` Borislav Petkov
2017-08-19 0:27 ` [PATCH v8 08/28] x86/mpx, x86/insn: Relocate insn util functions to a new insn-eval file Ricardo Neri
2017-09-06 15:54 ` Borislav Petkov
2017-09-06 19:27 ` Ricardo Neri
2017-08-19 0:27 ` [PATCH v8 09/28] x86/insn-eval: Do not BUG on invalid register type Ricardo Neri
2017-09-07 17:54 ` Borislav Petkov
2017-09-07 20:27 ` Ricardo Neri
2017-08-19 0:27 ` [PATCH v8 10/28] x86/insn-eval: Add a utility function to get register offsets Ricardo Neri
2017-09-08 13:35 ` Borislav Petkov
2017-09-14 18:30 ` Ricardo Neri
2017-08-19 0:27 ` [PATCH v8 11/28] x86/insn-eval: Add utility function to identify string instructions Ricardo Neri
2017-09-08 13:57 ` Borislav Petkov
2017-09-14 18:30 ` Ricardo Neri
2017-08-19 0:27 ` [PATCH v8 12/28] x86/insn-eval: Add utility functions to get segment selector Ricardo Neri
2017-09-26 10:43 ` Borislav Petkov
2017-09-27 4:21 ` Ricardo Neri [this message]
2017-09-27 11:47 ` Borislav Petkov
2017-09-27 22:32 ` Ricardo Neri
2017-09-28 9:36 ` Borislav Petkov
2017-09-29 6:06 ` Ricardo Neri
2017-09-29 11:56 ` Borislav Petkov
2017-10-04 16:47 ` Ricardo Neri
2017-08-19 0:27 ` [PATCH v8 13/28] x86/insn-eval: Add utility function to get segment descriptor Ricardo Neri
2017-09-26 18:05 ` Borislav Petkov
2017-09-27 17:39 ` Neri, Ricardo
2017-08-19 0:27 ` [PATCH v8 14/28] x86/insn-eval: Add utility functions to get segment descriptor base address and limit Ricardo Neri
2017-08-19 0:27 ` [PATCH v8 15/28] x86/insn-eval: Add function to get default params of code segment Ricardo Neri
2017-08-19 0:27 ` [PATCH v8 16/28] x86/insn-eval: Indicate a 32-bit displacement if ModRM.mod is 0 and ModRM.rm is 101b Ricardo Neri
2017-08-19 0:27 ` [PATCH v8 17/28] x86/insn-eval: Incorporate segment base in linear address computation Ricardo Neri
2017-08-19 0:27 ` [PATCH v8 18/28] x86/insn-eval: Add support to resolve 32-bit address encodings Ricardo Neri
2017-08-19 0:28 ` [PATCH v8 19/28] x86/insn-eval: Add wrapper function for 32 and 64-bit addresses Ricardo Neri
2017-08-19 0:28 ` [PATCH v8 20/28] x86/insn-eval: Handle 32-bit address encodings in virtual-8086 mode Ricardo Neri
2017-08-19 0:28 ` [PATCH v8 21/28] x86/insn-eval: Add support to resolve 16-bit addressing encodings Ricardo Neri
2017-08-19 0:28 ` [PATCH v8 22/28] x86/cpufeature: Add User-Mode Instruction Prevention definitions Ricardo Neri
2017-08-19 0:28 ` [PATCH v8 23/28] x86: Add emulation code for UMIP instructions Ricardo Neri
2017-08-19 0:28 ` [PATCH v8 24/28] x86/umip: Force a page fault when unable to copy emulated result to user Ricardo Neri
2017-08-19 0:28 ` [PATCH v8 25/28] x86: Enable User-Mode Instruction Prevention Ricardo Neri
2017-08-19 0:28 ` [PATCH v8 26/28] x86/traps: Fixup general protection faults caused by UMIP Ricardo Neri
2017-08-19 0:28 ` [PATCH v8 27/28] selftests/x86: Add tests for User-Mode Instruction Prevention Ricardo Neri
2017-08-19 0:28 ` [PATCH v8 28/28] selftests/x86: Add tests for instruction str and sldt Ricardo Neri
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=1506486104.8286.142.camel@linux.intel.com \
--to=ricardo.neri-calderon@linux.intel.com \
--cc=acme@redhat.com \
--cc=adam.buchbinder@gmail.com \
--cc=adrian.hunter@intel.com \
--cc=akpm@linux-foundation.org \
--cc=bp@suse.de \
--cc=brgerst@gmail.com \
--cc=cmetcalf@mellanox.com \
--cc=colin.king@canonical.com \
--cc=corbet@lwn.net \
--cc=dave.hansen@linux.intel.com \
--cc=dvyukov@google.com \
--cc=hpa@zytor.com \
--cc=jslaby@suse.cz \
--cc=keescook@chromium.org \
--cc=linux-kernel@vger.kernel.org \
--cc=lstoakes@gmail.com \
--cc=luto@kernel.org \
--cc=mhiramat@kernel.org \
--cc=mingo@redhat.com \
--cc=mst@redhat.com \
--cc=paul.gortmaker@windriver.com \
--cc=pbonzini@redhat.com \
--cc=peterz@infradead.org \
--cc=qiaowei.ren@intel.com \
--cc=ravi.v.shankar@intel.com \
--cc=ray.huang@amd.com \
--cc=shuah@kernel.org \
--cc=slaoub@gmail.com \
--cc=tglx@linutronix.de \
--cc=thgarnie@google.com \
--cc=vbabka@suse.cz \
--cc=x86@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 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.