From: Namhyung Kim <namhyung@gmail.com> To: Alexei Starovoitov <ast@plumgrid.com> Cc: "David S. Miller" <davem@davemloft.net>, Ingo Molnar <mingo@kernel.org>, Linus Torvalds <torvalds@linux-foundation.org>, Steven Rostedt <rostedt@goodmis.org>, Daniel Borkmann <dborkman@redhat.com>, Chema Gonzalez <chema@google.com>, Eric Dumazet <edumazet@google.com>, Peter Zijlstra <a.p.zijlstra@chello.nl>, Arnaldo Carvalho de Melo <acme@infradead.org>, Jiri Olsa <jolsa@redhat.com>, Thomas Gleixner <tglx@linutronix.de>, "H. Peter Anvin" <hpa@zytor.com>, Andrew Morton <akpm@linux-foundation.org>, Kees Cook <keescook@chromium.org>, linux-api@vger.kernel.org, netdev@vger.kernel.org, linux-kernel@vger.kernel.org Subject: Re: [PATCH RFC net-next 08/14] bpf: add eBPF verifier Date: Wed, 02 Jul 2014 14:05:56 +0900 [thread overview] Message-ID: <87y4wc4aff.fsf@sejong.aot.lge.com> (raw) In-Reply-To: <1403913966-4927-9-git-send-email-ast@plumgrid.com> (Alexei Starovoitov's message of "Fri, 27 Jun 2014 17:06:00 -0700") Mostly questions and few nitpicks.. :) On Fri, 27 Jun 2014 17:06:00 -0700, Alexei Starovoitov wrote: > +/* types of values: > + * - stored in an eBPF register > + * - passed into helper functions as an argument > + * - returned from helper functions > + */ > +enum bpf_reg_type { > + INVALID_PTR, /* reg doesn't contain a valid pointer */ I don't think it's a good name. The INVALID_PTR can be read as it contains a "pointer" which is invalid. Maybe INTEGER, NUMBER or something different can be used. And I think the struct reg_state->ptr should be renamed also. > + PTR_TO_CTX, /* reg points to bpf_context */ > + PTR_TO_MAP, /* reg points to map element value */ > + PTR_TO_MAP_CONDITIONAL, /* points to map element value or NULL */ > + PTR_TO_STACK, /* reg == frame_pointer */ > + PTR_TO_STACK_IMM, /* reg == frame_pointer + imm */ > + PTR_TO_STACK_IMM_MAP_KEY, /* pointer to stack used as map key */ > + PTR_TO_STACK_IMM_MAP_VALUE, /* pointer to stack used as map elem */ So, these PTR_TO_STACK_IMM[_*] types are only for function argument, right? I guessed it could be used to access memory in general too, but then I thought it'd make verification complicated.. And I also agree that it'd better splitting reg types and function argument constraints. > + RET_INTEGER, /* function returns integer */ > + RET_VOID, /* function returns void */ > + CONST_ARG, /* function expects integer constant argument */ > + CONST_ARG_MAP_ID, /* int const argument that is used as map_id */ That means a map id should always be a constant (for verification), right? > + /* int const argument indicating number of bytes accessed from stack > + * previous function argument must be ptr_to_stack_imm > + */ > + CONST_ARG_STACK_IMM_SIZE, > +}; [SNIP] > + > +/* check read/write into map element returned by bpf_table_lookup() */ > +static int check_table_access(struct verifier_env *env, int regno, int off, > + int size) I guess the "table" is an old name of the "map"? > +{ > + struct bpf_map *map; > + int map_id = env->cur_state.regs[regno].imm; > + > + _(get_map_info(env, map_id, &map)); > + > + if (off < 0 || off + size > map->value_size) { > + verbose("invalid access to map_id=%d leaf_size=%d off=%d size=%d\n", > + map_id, map->value_size, off, size); > + return -EACCES; > + } > + return 0; > +} [SNIP] > +static int check_mem_access(struct verifier_env *env, int regno, int off, > + int bpf_size, enum bpf_access_type t, > + int value_regno) > +{ > + struct verifier_state *state = &env->cur_state; > + int size; > + > + _(size = bpf_size_to_bytes(bpf_size)); > + > + if (off % size != 0) { > + verbose("misaligned access off %d size %d\n", off, size); > + return -EACCES; > + } > + > + if (state->regs[regno].ptr == PTR_TO_MAP) { > + _(check_table_access(env, regno, off, size)); > + if (t == BPF_READ) > + mark_reg_no_ptr(state->regs, value_regno); > + } else if (state->regs[regno].ptr == PTR_TO_CTX) { > + _(check_ctx_access(env, off, size, t)); > + if (t == BPF_READ) > + mark_reg_no_ptr(state->regs, value_regno); > + } else if (state->regs[regno].ptr == PTR_TO_STACK) { > + if (off >= 0 || off < -MAX_BPF_STACK) { > + verbose("invalid stack off=%d size=%d\n", off, size); > + return -EACCES; > + } So memory (stack) access is only allowed for a stack base regsiter and a constant offset, right? > + if (t == BPF_WRITE) > + _(check_stack_write(state, off, size, value_regno)); > + else > + _(check_stack_read(state, off, size, value_regno)); > + } else { > + verbose("R%d invalid mem access '%s'\n", > + regno, reg_type_str[state->regs[regno].ptr]); > + return -EACCES; > + } > + return 0; > +} [SNIP] > +static int check_call(struct verifier_env *env, int func_id) > +{ > + struct verifier_state *state = &env->cur_state; > + const struct bpf_func_proto *fn = NULL; > + struct reg_state *regs = state->regs; > + struct bpf_map *map = NULL; > + struct reg_state *reg; > + int map_id = -1; > + int i; > + > + /* find function prototype */ > + if (func_id <= 0 || func_id >= __BPF_FUNC_MAX_ID) { > + verbose("invalid func %d\n", func_id); > + return -EINVAL; > + } > + > + if (env->prog->info->ops->get_func_proto) > + fn = env->prog->info->ops->get_func_proto(func_id); > + > + if (!fn || (fn->ret_type != RET_INTEGER && > + fn->ret_type != PTR_TO_MAP_CONDITIONAL && > + fn->ret_type != RET_VOID)) { > + verbose("unknown func %d\n", func_id); > + return -EINVAL; > + } > + > + /* check args */ > + _(check_func_arg(env, BPF_REG_1, fn->arg1_type, &map_id, &map)); > + _(check_func_arg(env, BPF_REG_2, fn->arg2_type, &map_id, &map)); > + _(check_func_arg(env, BPF_REG_3, fn->arg3_type, &map_id, &map)); > + _(check_func_arg(env, BPF_REG_4, fn->arg4_type, &map_id, &map)); Missing BPF_REG_5? > + > + /* reset caller saved regs */ > + for (i = 0; i < CALLER_SAVED_REGS; i++) { > + reg = regs + caller_saved[i]; > + reg->read_ok = false; > + reg->ptr = INVALID_PTR; > + reg->imm = 0xbadbad; > + } > + > + /* update return register */ > + reg = regs + BPF_REG_0; > + if (fn->ret_type == RET_INTEGER) { > + reg->read_ok = true; > + reg->ptr = INVALID_PTR; > + } else if (fn->ret_type != RET_VOID) { > + reg->read_ok = true; > + reg->ptr = fn->ret_type; > + if (fn->ret_type == PTR_TO_MAP_CONDITIONAL) > + /* > + * remember map_id, so that check_table_access() > + * can check 'value_size' boundary of memory access > + * to map element returned from bpf_table_lookup() > + */ > + reg->imm = map_id; > + } > + return 0; > +} [SNIP] > +#define PEAK_INT() \ s/PEAK/PEEK/ ? Thanks, Namhyung > + ({ \ > + int _ret; \ > + if (cur_stack == 0) \ > + _ret = -1; \ > + else \ > + _ret = stack[cur_stack - 1]; \ > + _ret; \ > + }) > + > +#define POP_INT() \ > + ({ \ > + int _ret; \ > + if (cur_stack == 0) \ > + _ret = -1; \ > + else \ > + _ret = stack[--cur_stack]; \ > + _ret; \ > + })
WARNING: multiple messages have this Message-ID (diff)
From: Namhyung Kim <namhyung-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> To: Alexei Starovoitov <ast-uqk4Ao+rVK5Wk0Htik3J/w@public.gmane.org> Cc: "David S. Miller" <davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>, Ingo Molnar <mingo-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>, Linus Torvalds <torvalds-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b@public.gmane.org>, Steven Rostedt <rostedt-nx8X9YLhiw1AfugRpC6u6w@public.gmane.org>, Daniel Borkmann <dborkman-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>, Chema Gonzalez <chema-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>, Eric Dumazet <edumazet-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>, Peter Zijlstra <a.p.zijlstra-/NLkJaSkS4VmR6Xm/wNWPw@public.gmane.org>, Arnaldo Carvalho de Melo <acme-wEGCiKHe2LqWVfeAwA7xHQ@public.gmane.org>, Jiri Olsa <jolsa-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>, Thomas Gleixner <tglx-hfZtesqFncYOwBW4kG4KsQ@public.gmane.org>, "H. Peter Anvin" <hpa-YMNOUZJC4hwAvxtiuMwx3w@public.gmane.org>, Andrew Morton <akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b@public.gmane.org>, Kees Cook <keescook-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>, linux-api-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, netdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org Subject: Re: [PATCH RFC net-next 08/14] bpf: add eBPF verifier Date: Wed, 02 Jul 2014 14:05:56 +0900 [thread overview] Message-ID: <87y4wc4aff.fsf@sejong.aot.lge.com> (raw) In-Reply-To: <1403913966-4927-9-git-send-email-ast-uqk4Ao+rVK5Wk0Htik3J/w@public.gmane.org> (Alexei Starovoitov's message of "Fri, 27 Jun 2014 17:06:00 -0700") Mostly questions and few nitpicks.. :) On Fri, 27 Jun 2014 17:06:00 -0700, Alexei Starovoitov wrote: > +/* types of values: > + * - stored in an eBPF register > + * - passed into helper functions as an argument > + * - returned from helper functions > + */ > +enum bpf_reg_type { > + INVALID_PTR, /* reg doesn't contain a valid pointer */ I don't think it's a good name. The INVALID_PTR can be read as it contains a "pointer" which is invalid. Maybe INTEGER, NUMBER or something different can be used. And I think the struct reg_state->ptr should be renamed also. > + PTR_TO_CTX, /* reg points to bpf_context */ > + PTR_TO_MAP, /* reg points to map element value */ > + PTR_TO_MAP_CONDITIONAL, /* points to map element value or NULL */ > + PTR_TO_STACK, /* reg == frame_pointer */ > + PTR_TO_STACK_IMM, /* reg == frame_pointer + imm */ > + PTR_TO_STACK_IMM_MAP_KEY, /* pointer to stack used as map key */ > + PTR_TO_STACK_IMM_MAP_VALUE, /* pointer to stack used as map elem */ So, these PTR_TO_STACK_IMM[_*] types are only for function argument, right? I guessed it could be used to access memory in general too, but then I thought it'd make verification complicated.. And I also agree that it'd better splitting reg types and function argument constraints. > + RET_INTEGER, /* function returns integer */ > + RET_VOID, /* function returns void */ > + CONST_ARG, /* function expects integer constant argument */ > + CONST_ARG_MAP_ID, /* int const argument that is used as map_id */ That means a map id should always be a constant (for verification), right? > + /* int const argument indicating number of bytes accessed from stack > + * previous function argument must be ptr_to_stack_imm > + */ > + CONST_ARG_STACK_IMM_SIZE, > +}; [SNIP] > + > +/* check read/write into map element returned by bpf_table_lookup() */ > +static int check_table_access(struct verifier_env *env, int regno, int off, > + int size) I guess the "table" is an old name of the "map"? > +{ > + struct bpf_map *map; > + int map_id = env->cur_state.regs[regno].imm; > + > + _(get_map_info(env, map_id, &map)); > + > + if (off < 0 || off + size > map->value_size) { > + verbose("invalid access to map_id=%d leaf_size=%d off=%d size=%d\n", > + map_id, map->value_size, off, size); > + return -EACCES; > + } > + return 0; > +} [SNIP] > +static int check_mem_access(struct verifier_env *env, int regno, int off, > + int bpf_size, enum bpf_access_type t, > + int value_regno) > +{ > + struct verifier_state *state = &env->cur_state; > + int size; > + > + _(size = bpf_size_to_bytes(bpf_size)); > + > + if (off % size != 0) { > + verbose("misaligned access off %d size %d\n", off, size); > + return -EACCES; > + } > + > + if (state->regs[regno].ptr == PTR_TO_MAP) { > + _(check_table_access(env, regno, off, size)); > + if (t == BPF_READ) > + mark_reg_no_ptr(state->regs, value_regno); > + } else if (state->regs[regno].ptr == PTR_TO_CTX) { > + _(check_ctx_access(env, off, size, t)); > + if (t == BPF_READ) > + mark_reg_no_ptr(state->regs, value_regno); > + } else if (state->regs[regno].ptr == PTR_TO_STACK) { > + if (off >= 0 || off < -MAX_BPF_STACK) { > + verbose("invalid stack off=%d size=%d\n", off, size); > + return -EACCES; > + } So memory (stack) access is only allowed for a stack base regsiter and a constant offset, right? > + if (t == BPF_WRITE) > + _(check_stack_write(state, off, size, value_regno)); > + else > + _(check_stack_read(state, off, size, value_regno)); > + } else { > + verbose("R%d invalid mem access '%s'\n", > + regno, reg_type_str[state->regs[regno].ptr]); > + return -EACCES; > + } > + return 0; > +} [SNIP] > +static int check_call(struct verifier_env *env, int func_id) > +{ > + struct verifier_state *state = &env->cur_state; > + const struct bpf_func_proto *fn = NULL; > + struct reg_state *regs = state->regs; > + struct bpf_map *map = NULL; > + struct reg_state *reg; > + int map_id = -1; > + int i; > + > + /* find function prototype */ > + if (func_id <= 0 || func_id >= __BPF_FUNC_MAX_ID) { > + verbose("invalid func %d\n", func_id); > + return -EINVAL; > + } > + > + if (env->prog->info->ops->get_func_proto) > + fn = env->prog->info->ops->get_func_proto(func_id); > + > + if (!fn || (fn->ret_type != RET_INTEGER && > + fn->ret_type != PTR_TO_MAP_CONDITIONAL && > + fn->ret_type != RET_VOID)) { > + verbose("unknown func %d\n", func_id); > + return -EINVAL; > + } > + > + /* check args */ > + _(check_func_arg(env, BPF_REG_1, fn->arg1_type, &map_id, &map)); > + _(check_func_arg(env, BPF_REG_2, fn->arg2_type, &map_id, &map)); > + _(check_func_arg(env, BPF_REG_3, fn->arg3_type, &map_id, &map)); > + _(check_func_arg(env, BPF_REG_4, fn->arg4_type, &map_id, &map)); Missing BPF_REG_5? > + > + /* reset caller saved regs */ > + for (i = 0; i < CALLER_SAVED_REGS; i++) { > + reg = regs + caller_saved[i]; > + reg->read_ok = false; > + reg->ptr = INVALID_PTR; > + reg->imm = 0xbadbad; > + } > + > + /* update return register */ > + reg = regs + BPF_REG_0; > + if (fn->ret_type == RET_INTEGER) { > + reg->read_ok = true; > + reg->ptr = INVALID_PTR; > + } else if (fn->ret_type != RET_VOID) { > + reg->read_ok = true; > + reg->ptr = fn->ret_type; > + if (fn->ret_type == PTR_TO_MAP_CONDITIONAL) > + /* > + * remember map_id, so that check_table_access() > + * can check 'value_size' boundary of memory access > + * to map element returned from bpf_table_lookup() > + */ > + reg->imm = map_id; > + } > + return 0; > +} [SNIP] > +#define PEAK_INT() \ s/PEAK/PEEK/ ? Thanks, Namhyung > + ({ \ > + int _ret; \ > + if (cur_stack == 0) \ > + _ret = -1; \ > + else \ > + _ret = stack[cur_stack - 1]; \ > + _ret; \ > + }) > + > +#define POP_INT() \ > + ({ \ > + int _ret; \ > + if (cur_stack == 0) \ > + _ret = -1; \ > + else \ > + _ret = stack[--cur_stack]; \ > + _ret; \ > + })
next prev parent reply other threads:[~2014-07-02 5:06 UTC|newest] Thread overview: 108+ messages / expand[flat|nested] mbox.gz Atom feed top 2014-06-28 0:05 [PATCH RFC net-next 00/14] BPF syscall, maps, verifier, samples Alexei Starovoitov 2014-06-28 0:05 ` [PATCH RFC net-next 01/14] net: filter: split filter.c into two files Alexei Starovoitov 2014-07-02 4:23 ` Namhyung Kim 2014-07-02 4:23 ` Namhyung Kim 2014-07-02 5:35 ` Alexei Starovoitov 2014-07-02 5:35 ` Alexei Starovoitov 2014-06-28 0:05 ` [PATCH RFC net-next 02/14] net: filter: split filter.h and expose eBPF to user space Alexei Starovoitov 2014-06-28 0:05 ` [PATCH RFC net-next 03/14] bpf: introduce syscall(BPF, ...) and BPF maps Alexei Starovoitov 2014-06-28 0:16 ` Andy Lutomirski 2014-06-28 5:55 ` Alexei Starovoitov 2014-06-28 6:25 ` Andy Lutomirski 2014-06-28 6:25 ` Andy Lutomirski 2014-06-28 6:43 ` Alexei Starovoitov 2014-06-28 6:43 ` Alexei Starovoitov 2014-06-28 15:34 ` Andy Lutomirski 2014-06-28 15:34 ` Andy Lutomirski 2014-06-28 20:49 ` Alexei Starovoitov 2014-06-28 20:49 ` Alexei Starovoitov 2014-06-29 1:52 ` Andy Lutomirski 2014-06-29 1:52 ` Andy Lutomirski 2014-06-29 6:36 ` Alexei Starovoitov 2014-06-29 6:36 ` Alexei Starovoitov 2014-06-30 22:09 ` Andy Lutomirski 2014-06-30 22:09 ` Andy Lutomirski 2014-07-01 5:47 ` Alexei Starovoitov 2014-07-01 15:11 ` Andy Lutomirski 2014-07-01 15:11 ` Andy Lutomirski 2014-07-02 5:33 ` Alexei Starovoitov 2014-07-02 5:33 ` Alexei Starovoitov 2014-07-03 1:43 ` Andy Lutomirski 2014-07-03 1:43 ` Andy Lutomirski 2014-07-03 2:29 ` Alexei Starovoitov 2014-07-04 15:17 ` Andy Lutomirski 2014-07-04 15:17 ` Andy Lutomirski 2014-07-05 21:59 ` Alexei Starovoitov 2014-06-28 0:05 ` [PATCH RFC net-next 04/14] bpf: update MAINTAINERS entry Alexei Starovoitov 2014-06-28 0:18 ` Joe Perches 2014-06-28 5:59 ` Alexei Starovoitov 2014-06-28 5:59 ` Alexei Starovoitov 2014-06-28 0:05 ` [PATCH RFC net-next 05/14] bpf: add lookup/update/delete/iterate methods to BPF maps Alexei Starovoitov 2014-06-28 0:05 ` [PATCH RFC net-next 06/14] bpf: add hashtable type of " Alexei Starovoitov 2014-06-28 0:05 ` [PATCH RFC net-next 07/14] bpf: expand BPF syscall with program load/unload Alexei Starovoitov 2014-06-28 0:19 ` Andy Lutomirski 2014-06-28 0:19 ` Andy Lutomirski 2014-06-28 6:12 ` Alexei Starovoitov 2014-06-28 6:28 ` Andy Lutomirski 2014-06-28 7:26 ` Alexei Starovoitov 2014-06-28 7:26 ` Alexei Starovoitov 2014-06-28 15:21 ` Greg KH 2014-06-28 15:21 ` Greg KH 2014-06-28 15:35 ` Andy Lutomirski 2014-06-30 20:39 ` Alexei Starovoitov 2014-06-30 10:06 ` David Laight 2014-06-30 10:06 ` David Laight 2014-06-28 0:06 ` [PATCH RFC net-next 08/14] bpf: add eBPF verifier Alexei Starovoitov 2014-06-28 16:01 ` Andy Lutomirski 2014-06-28 16:01 ` Andy Lutomirski 2014-06-28 20:25 ` Alexei Starovoitov 2014-06-28 20:25 ` Alexei Starovoitov 2014-06-29 1:58 ` Andy Lutomirski 2014-06-29 6:20 ` Alexei Starovoitov 2014-06-29 6:20 ` Alexei Starovoitov 2014-07-01 8:05 ` Daniel Borkmann 2014-07-01 8:05 ` Daniel Borkmann 2014-07-01 20:04 ` Alexei Starovoitov 2014-07-01 20:04 ` Alexei Starovoitov 2014-07-02 8:11 ` David Laight 2014-07-02 8:11 ` David Laight 2014-07-02 22:43 ` Alexei Starovoitov 2014-07-02 22:43 ` Alexei Starovoitov 2014-07-02 5:05 ` Namhyung Kim [this message] 2014-07-02 5:05 ` Namhyung Kim 2014-07-02 5:57 ` Alexei Starovoitov 2014-07-02 22:22 ` Chema Gonzalez 2014-07-02 23:04 ` Alexei Starovoitov 2014-07-02 23:04 ` Alexei Starovoitov 2014-07-02 23:35 ` Chema Gonzalez 2014-07-03 0:01 ` Alexei Starovoitov 2014-07-03 0:01 ` Alexei Starovoitov 2014-07-03 9:13 ` David Laight 2014-07-03 9:13 ` David Laight 2014-07-03 17:41 ` Alexei Starovoitov 2014-06-28 0:06 ` [PATCH RFC net-next 09/14] bpf: allow eBPF programs to use maps Alexei Starovoitov 2014-06-28 0:06 ` Alexei Starovoitov 2014-06-28 0:06 ` [PATCH RFC net-next 10/14] net: sock: allow eBPF programs to be attached to sockets Alexei Starovoitov 2014-06-28 0:06 ` [PATCH RFC net-next 11/14] tracing: allow eBPF programs to be attached to events Alexei Starovoitov 2014-07-01 8:30 ` Daniel Borkmann 2014-07-01 8:30 ` Daniel Borkmann 2014-07-01 20:06 ` Alexei Starovoitov 2014-07-01 20:06 ` Alexei Starovoitov 2014-07-02 5:32 ` Namhyung Kim 2014-07-02 5:32 ` Namhyung Kim 2014-07-02 6:14 ` Alexei Starovoitov 2014-07-02 6:14 ` Alexei Starovoitov 2014-07-02 6:39 ` Namhyung Kim 2014-07-02 7:29 ` Alexei Starovoitov 2014-06-28 0:06 ` [PATCH RFC net-next 12/14] samples: bpf: add mini eBPF library to manipulate maps and programs Alexei Starovoitov 2014-06-28 0:06 ` [PATCH RFC net-next 13/14] samples: bpf: example of stateful socket filtering Alexei Starovoitov 2014-06-28 0:21 ` Andy Lutomirski 2014-06-28 6:21 ` Alexei Starovoitov 2014-06-28 6:21 ` Alexei Starovoitov 2014-06-28 0:06 ` [PATCH RFC net-next 14/14] samples: bpf: example of tracing filters with eBPF Alexei Starovoitov 2014-06-30 23:09 ` [PATCH RFC net-next 00/14] BPF syscall, maps, verifier, samples Kees Cook 2014-06-30 23:09 ` Kees Cook 2014-07-01 7:18 ` Daniel Borkmann 2014-07-01 7:18 ` Daniel Borkmann 2014-07-02 16:39 ` Kees Cook 2014-07-02 16:39 ` Kees Cook
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=87y4wc4aff.fsf@sejong.aot.lge.com \ --to=namhyung@gmail.com \ --cc=a.p.zijlstra@chello.nl \ --cc=acme@infradead.org \ --cc=akpm@linux-foundation.org \ --cc=ast@plumgrid.com \ --cc=chema@google.com \ --cc=davem@davemloft.net \ --cc=dborkman@redhat.com \ --cc=edumazet@google.com \ --cc=hpa@zytor.com \ --cc=jolsa@redhat.com \ --cc=keescook@chromium.org \ --cc=linux-api@vger.kernel.org \ --cc=linux-kernel@vger.kernel.org \ --cc=mingo@kernel.org \ --cc=netdev@vger.kernel.org \ --cc=rostedt@goodmis.org \ --cc=tglx@linutronix.de \ --cc=torvalds@linux-foundation.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: linkBe 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.