diff mbox series

[v2,bpf-next,2/6] bpf: propagate poke descriptors to subprograms

Message ID 20200721115321.3099-3-maciej.fijalkowski@intel.com
State Changes Requested
Delegated to: BPF Maintainers
Headers show
Series bpf: tailcalls in BPF subprograms | expand

Commit Message

Maciej Fijalkowski July 21, 2020, 11:53 a.m. UTC
Previously, there was no need for poke descriptors being present in
subprogram's bpf_prog_aux struct since tailcalls were simply not allowed
in them. Each subprog is JITed independently so in order to enable
JITing such subprograms, simply copy poke descriptors from main program
to subprogram's poke tab.

Add also subprog's aux struct to the BPF map poke_progs list by calling
on it map_poke_track().

Signed-off-by: Maciej Fijalkowski <maciej.fijalkowski@intel.com>
---
 kernel/bpf/verifier.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

Comments

Daniel Borkmann July 22, 2020, 2:40 p.m. UTC | #1
On 7/21/20 1:53 PM, Maciej Fijalkowski wrote:
> Previously, there was no need for poke descriptors being present in
> subprogram's bpf_prog_aux struct since tailcalls were simply not allowed
> in them. Each subprog is JITed independently so in order to enable
> JITing such subprograms, simply copy poke descriptors from main program
> to subprogram's poke tab.
> 
> Add also subprog's aux struct to the BPF map poke_progs list by calling
> on it map_poke_track().
> 
> Signed-off-by: Maciej Fijalkowski <maciej.fijalkowski@intel.com>
> ---
>   kernel/bpf/verifier.c | 20 ++++++++++++++++++++
>   1 file changed, 20 insertions(+)
> 
> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index 3c1efc9d08fd..3428edf85220 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -9936,6 +9936,9 @@ static int jit_subprogs(struct bpf_verifier_env *env)
>   		goto out_undo_insn;
>   
>   	for (i = 0; i < env->subprog_cnt; i++) {
> +		struct bpf_map *map_ptr;
> +		int j;
> +
>   		subprog_start = subprog_end;
>   		subprog_end = env->subprog_info[i + 1].start;
>   
> @@ -9960,6 +9963,23 @@ static int jit_subprogs(struct bpf_verifier_env *env)
>   		func[i]->aux->btf = prog->aux->btf;
>   		func[i]->aux->func_info = prog->aux->func_info;
>   
> +		for (j = 0; j < prog->aux->size_poke_tab; j++) {
> +			int ret;
> +
> +			ret = bpf_jit_add_poke_descriptor(func[i],
> +							  &prog->aux->poke_tab[j]);
> +			if (ret < 0) {
> +				verbose(env, "adding tail call poke descriptor failed\n");
> +				goto out_free;
> +			}
> +			map_ptr = func[i]->aux->poke_tab[j].tail_call.map;
> +			ret = map_ptr->ops->map_poke_track(map_ptr, func[i]->aux);
> +			if (ret < 0) {
> +				verbose(env, "tracking tail call prog failed\n");
> +				goto out_free;
> +			}

Hmm, I don't think this is correct/complete. If some of these have been registered or
if later on the JIT'ing fails but the subprog is already exposed to the prog array then
it's /public/ at this point, so a later bpf_jit_free() in out_free will rip them mem
while doing live patching on prog updates leading to UAF.

> +		}
> +
>   		/* Use bpf_prog_F_tag to indicate functions in stack traces.
>   		 * Long term would need debug info to populate names
>   		 */
>
Maciej Fijalkowski July 22, 2020, 6:37 p.m. UTC | #2
On Wed, Jul 22, 2020 at 04:40:42PM +0200, Daniel Borkmann wrote:
> On 7/21/20 1:53 PM, Maciej Fijalkowski wrote:
> > Previously, there was no need for poke descriptors being present in
> > subprogram's bpf_prog_aux struct since tailcalls were simply not allowed
> > in them. Each subprog is JITed independently so in order to enable
> > JITing such subprograms, simply copy poke descriptors from main program
> > to subprogram's poke tab.
> > 
> > Add also subprog's aux struct to the BPF map poke_progs list by calling
> > on it map_poke_track().
> > 
> > Signed-off-by: Maciej Fijalkowski <maciej.fijalkowski@intel.com>
> > ---
> >   kernel/bpf/verifier.c | 20 ++++++++++++++++++++
> >   1 file changed, 20 insertions(+)
> > 
> > diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> > index 3c1efc9d08fd..3428edf85220 100644
> > --- a/kernel/bpf/verifier.c
> > +++ b/kernel/bpf/verifier.c
> > @@ -9936,6 +9936,9 @@ static int jit_subprogs(struct bpf_verifier_env *env)
> >   		goto out_undo_insn;
> >   	for (i = 0; i < env->subprog_cnt; i++) {
> > +		struct bpf_map *map_ptr;
> > +		int j;
> > +
> >   		subprog_start = subprog_end;
> >   		subprog_end = env->subprog_info[i + 1].start;
> > @@ -9960,6 +9963,23 @@ static int jit_subprogs(struct bpf_verifier_env *env)
> >   		func[i]->aux->btf = prog->aux->btf;
> >   		func[i]->aux->func_info = prog->aux->func_info;
> > +		for (j = 0; j < prog->aux->size_poke_tab; j++) {
> > +			int ret;
> > +
> > +			ret = bpf_jit_add_poke_descriptor(func[i],
> > +							  &prog->aux->poke_tab[j]);
> > +			if (ret < 0) {
> > +				verbose(env, "adding tail call poke descriptor failed\n");
> > +				goto out_free;
> > +			}
> > +			map_ptr = func[i]->aux->poke_tab[j].tail_call.map;
> > +			ret = map_ptr->ops->map_poke_track(map_ptr, func[i]->aux);
> > +			if (ret < 0) {
> > +				verbose(env, "tracking tail call prog failed\n");
> > +				goto out_free;
> > +			}
> 
> Hmm, I don't think this is correct/complete. If some of these have been registered or
> if later on the JIT'ing fails but the subprog is already exposed to the prog array then
> it's /public/ at this point, so a later bpf_jit_free() in out_free will rip them mem
> while doing live patching on prog updates leading to UAF.

Ugh. So if we would precede the out_free label with map_poke_untrack() on error
path - would that be sufficient?

> 
> > +		}
> > +
> >   		/* Use bpf_prog_F_tag to indicate functions in stack traces.
> >   		 * Long term would need debug info to populate names
> >   		 */
> > 
>
Daniel Borkmann July 22, 2020, 8:14 p.m. UTC | #3
On 7/22/20 8:37 PM, Maciej Fijalkowski wrote:
> On Wed, Jul 22, 2020 at 04:40:42PM +0200, Daniel Borkmann wrote:
>> On 7/21/20 1:53 PM, Maciej Fijalkowski wrote:
>>> Previously, there was no need for poke descriptors being present in
>>> subprogram's bpf_prog_aux struct since tailcalls were simply not allowed
>>> in them. Each subprog is JITed independently so in order to enable
>>> JITing such subprograms, simply copy poke descriptors from main program
>>> to subprogram's poke tab.
>>>
>>> Add also subprog's aux struct to the BPF map poke_progs list by calling
>>> on it map_poke_track().
>>>
>>> Signed-off-by: Maciej Fijalkowski <maciej.fijalkowski@intel.com>
>>> ---
>>>    kernel/bpf/verifier.c | 20 ++++++++++++++++++++
>>>    1 file changed, 20 insertions(+)
>>>
>>> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
>>> index 3c1efc9d08fd..3428edf85220 100644
>>> --- a/kernel/bpf/verifier.c
>>> +++ b/kernel/bpf/verifier.c
>>> @@ -9936,6 +9936,9 @@ static int jit_subprogs(struct bpf_verifier_env *env)
>>>    		goto out_undo_insn;
>>>    	for (i = 0; i < env->subprog_cnt; i++) {
>>> +		struct bpf_map *map_ptr;
>>> +		int j;
>>> +
>>>    		subprog_start = subprog_end;
>>>    		subprog_end = env->subprog_info[i + 1].start;
>>> @@ -9960,6 +9963,23 @@ static int jit_subprogs(struct bpf_verifier_env *env)
>>>    		func[i]->aux->btf = prog->aux->btf;
>>>    		func[i]->aux->func_info = prog->aux->func_info;
>>> +		for (j = 0; j < prog->aux->size_poke_tab; j++) {
>>> +			int ret;
>>> +
>>> +			ret = bpf_jit_add_poke_descriptor(func[i],
>>> +							  &prog->aux->poke_tab[j]);
>>> +			if (ret < 0) {
>>> +				verbose(env, "adding tail call poke descriptor failed\n");
>>> +				goto out_free;
>>> +			}
>>> +			map_ptr = func[i]->aux->poke_tab[j].tail_call.map;
>>> +			ret = map_ptr->ops->map_poke_track(map_ptr, func[i]->aux);
>>> +			if (ret < 0) {
>>> +				verbose(env, "tracking tail call prog failed\n");
>>> +				goto out_free;
>>> +			}
>>
>> Hmm, I don't think this is correct/complete. If some of these have been registered or
>> if later on the JIT'ing fails but the subprog is already exposed to the prog array then
>> it's /public/ at this point, so a later bpf_jit_free() in out_free will rip them mem
>> while doing live patching on prog updates leading to UAF.
> 
> Ugh. So if we would precede the out_free label with map_poke_untrack() on error
> path - would that be sufficient?

Yes that would be needed and should be sufficient since tracking/untracking/patching is
synchronized under the map's poke mutex lock.

>>> +		}
>>> +
>>>    		/* Use bpf_prog_F_tag to indicate functions in stack traces.
>>>    		 * Long term would need debug info to populate names
>>>    		 */
>>>
>>
diff mbox series

Patch

diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 3c1efc9d08fd..3428edf85220 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -9936,6 +9936,9 @@  static int jit_subprogs(struct bpf_verifier_env *env)
 		goto out_undo_insn;
 
 	for (i = 0; i < env->subprog_cnt; i++) {
+		struct bpf_map *map_ptr;
+		int j;
+
 		subprog_start = subprog_end;
 		subprog_end = env->subprog_info[i + 1].start;
 
@@ -9960,6 +9963,23 @@  static int jit_subprogs(struct bpf_verifier_env *env)
 		func[i]->aux->btf = prog->aux->btf;
 		func[i]->aux->func_info = prog->aux->func_info;
 
+		for (j = 0; j < prog->aux->size_poke_tab; j++) {
+			int ret;
+
+			ret = bpf_jit_add_poke_descriptor(func[i],
+							  &prog->aux->poke_tab[j]);
+			if (ret < 0) {
+				verbose(env, "adding tail call poke descriptor failed\n");
+				goto out_free;
+			}
+			map_ptr = func[i]->aux->poke_tab[j].tail_call.map;
+			ret = map_ptr->ops->map_poke_track(map_ptr, func[i]->aux);
+			if (ret < 0) {
+				verbose(env, "tracking tail call prog failed\n");
+				goto out_free;
+			}
+		}
+
 		/* Use bpf_prog_F_tag to indicate functions in stack traces.
 		 * Long term would need debug info to populate names
 		 */