All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH bpf-next v2] bpf: reject kfunc calls that overflow insn->imm
@ 2022-02-08 12:33 Hou Tao
  2022-02-08 16:57 ` Yonghong Song
  0 siblings, 1 reply; 4+ messages in thread
From: Hou Tao @ 2022-02-08 12:33 UTC (permalink / raw)
  To: Alexei Starovoitov
  Cc: Martin KaFai Lau, Yonghong Song, Daniel Borkmann,
	Andrii Nakryiko, Song Liu, John Fastabend, netdev, bpf, houtao1

Now kfunc call uses s32 to represent the offset between the address
of kfunc and __bpf_call_base, but it doesn't check whether or not
s32 will be overflowed, so add an extra checking to reject these
invalid kfunc calls.

Signed-off-by: Hou Tao <houtao1@huawei.com>
---
v2:
 * instead of checking the overflow in selftests, just reject
   these kfunc calls directly in verifier

v1: https://lore.kernel.org/bpf/20220206043107.18549-1-houtao1@huawei.com
---
 kernel/bpf/verifier.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index a39eedecc93a..fd836e64b701 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -1832,6 +1832,13 @@ static struct btf *find_kfunc_desc_btf(struct bpf_verifier_env *env,
 	return btf_vmlinux ?: ERR_PTR(-ENOENT);
 }
 
+static inline bool is_kfunc_call_imm_overflowed(unsigned long addr)
+{
+	unsigned long offset = BPF_CALL_IMM(addr);
+
+	return (unsigned long)(s32)offset != offset;
+}
+
 static int add_kfunc_call(struct bpf_verifier_env *env, u32 func_id, s16 offset)
 {
 	const struct btf_type *func, *func_proto;
@@ -1925,6 +1932,12 @@ static int add_kfunc_call(struct bpf_verifier_env *env, u32 func_id, s16 offset)
 		return -EINVAL;
 	}
 
+	if (is_kfunc_call_imm_overflowed(addr)) {
+		verbose(env, "address of kernel function %s is out of range\n",
+			func_name);
+		return -EINVAL;
+	}
+
 	desc = &tab->descs[tab->nr_descs++];
 	desc->func_id = func_id;
 	desc->imm = BPF_CALL_IMM(addr);
-- 
2.29.2


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH bpf-next v2] bpf: reject kfunc calls that overflow insn->imm
  2022-02-08 12:33 [PATCH bpf-next v2] bpf: reject kfunc calls that overflow insn->imm Hou Tao
@ 2022-02-08 16:57 ` Yonghong Song
  2022-02-09  6:20   ` Hou Tao
  0 siblings, 1 reply; 4+ messages in thread
From: Yonghong Song @ 2022-02-08 16:57 UTC (permalink / raw)
  To: Hou Tao, Alexei Starovoitov
  Cc: Martin KaFai Lau, Daniel Borkmann, Andrii Nakryiko, Song Liu,
	John Fastabend, netdev, bpf



On 2/8/22 4:33 AM, Hou Tao wrote:
> Now kfunc call uses s32 to represent the offset between the address
> of kfunc and __bpf_call_base, but it doesn't check whether or not
> s32 will be overflowed, so add an extra checking to reject these
> invalid kfunc calls.
> 
> Signed-off-by: Hou Tao <houtao1@huawei.com>
> ---
> v2:
>   * instead of checking the overflow in selftests, just reject
>     these kfunc calls directly in verifier
> 
> v1: https://lore.kernel.org/bpf/20220206043107.18549-1-houtao1@huawei.com
> ---
>   kernel/bpf/verifier.c | 13 +++++++++++++
>   1 file changed, 13 insertions(+)
> 
> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index a39eedecc93a..fd836e64b701 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -1832,6 +1832,13 @@ static struct btf *find_kfunc_desc_btf(struct bpf_verifier_env *env,
>   	return btf_vmlinux ?: ERR_PTR(-ENOENT);
>   }
>   
> +static inline bool is_kfunc_call_imm_overflowed(unsigned long addr)
> +{
> +	unsigned long offset = BPF_CALL_IMM(addr);
> +
> +	return (unsigned long)(s32)offset != offset;
> +}
> +
>   static int add_kfunc_call(struct bpf_verifier_env *env, u32 func_id, s16 offset)
>   {
>   	const struct btf_type *func, *func_proto;
> @@ -1925,6 +1932,12 @@ static int add_kfunc_call(struct bpf_verifier_env *env, u32 func_id, s16 offset)
>   		return -EINVAL;
>   	}
>   
> +	if (is_kfunc_call_imm_overflowed(addr)) {
> +		verbose(env, "address of kernel function %s is out of range\n",
> +			func_name);
> +		return -EINVAL;
> +	}
> +
>   	desc = &tab->descs[tab->nr_descs++];
>   	desc->func_id = func_id;
>   	desc->imm = BPF_CALL_IMM(addr);

Thanks, I would like to call BPF_CALL_IMM only once and keep checking 
overflow and setting desc->imm close to each other. How about the 
following not-compile-tested code

	unsigned long call_imm;

	...
	call_imm = BPF_CALL_IMM(addr);
	/* some comment here */
	if ((unsigned long)(s32)call_imm != call_imm) {
		verbose(env, ...);
		return -EINVAL;
	} else {
		desc->imm = call_imm;
	}

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH bpf-next v2] bpf: reject kfunc calls that overflow insn->imm
  2022-02-08 16:57 ` Yonghong Song
@ 2022-02-09  6:20   ` Hou Tao
  2022-02-09 15:31     ` Yonghong Song
  0 siblings, 1 reply; 4+ messages in thread
From: Hou Tao @ 2022-02-09  6:20 UTC (permalink / raw)
  To: Yonghong Song, Alexei Starovoitov
  Cc: Martin KaFai Lau, Daniel Borkmann, Andrii Nakryiko, Song Liu,
	John Fastabend, netdev, bpf

Hi,

On 2/9/2022 12:57 AM, Yonghong Song wrote:
>
>
> On 2/8/22 4:33 AM, Hou Tao wrote:
>> Now kfunc call uses s32 to represent the offset between the address
>> of kfunc and __bpf_call_base, but it doesn't check whether or not
>> s32 will be overflowed, so add an extra checking to reject these
>> invalid kfunc calls.
>>
>> Signed-off-by: Hou Tao <houtao1@huawei.com>
>> ---
>> v2:
>>   * instead of checking the overflow in selftests, just reject
>>     these kfunc calls directly in verifier
>>
>> v1: https://lore.kernel.org/bpf/20220206043107.18549-1-houtao1@huawei.com
>> ---
>>   kernel/bpf/verifier.c | 13 +++++++++++++
>>   1 file changed, 13 insertions(+)
>>
>> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
>> index a39eedecc93a..fd836e64b701 100644
>> --- a/kernel/bpf/verifier.c
>> +++ b/kernel/bpf/verifier.c
>> @@ -1832,6 +1832,13 @@ static struct btf *find_kfunc_desc_btf(struct
>> bpf_verifier_env *env,
>>       return btf_vmlinux ?: ERR_PTR(-ENOENT);
>>   }
>>   +static inline bool is_kfunc_call_imm_overflowed(unsigned long addr)
>> +{
>> +    unsigned long offset = BPF_CALL_IMM(addr);
>> +
>> +    return (unsigned long)(s32)offset != offset;
>> +}
>> +
>>   static int add_kfunc_call(struct bpf_verifier_env *env, u32 func_id, s16
>> offset)
>>   {
>>       const struct btf_type *func, *func_proto;
>> @@ -1925,6 +1932,12 @@ static int add_kfunc_call(struct bpf_verifier_env
>> *env, u32 func_id, s16 offset)
>>           return -EINVAL;
>>       }
>>   +    if (is_kfunc_call_imm_overflowed(addr)) {
>> +        verbose(env, "address of kernel function %s is out of range\n",
>> +            func_name);
>> +        return -EINVAL;
>> +    }
>> +
>>       desc = &tab->descs[tab->nr_descs++];
>>       desc->func_id = func_id;
>>       desc->imm = BPF_CALL_IMM(addr);
>
> Thanks, I would like to call BPF_CALL_IMM only once and keep checking overflow
> and setting desc->imm close to each other. How about the following
> not-compile-tested code
>
>     unsigned long call_imm;
>
>     ...
>     call_imm = BPF_CALL_IMM(addr);
>     /* some comment here */
>     if ((unsigned long)(s32)call_imm != call_imm) {
>         verbose(env, ...);
>         return -EINVAL;
>     } else {
>         desc->imm = call_imm;
>     }
call BPF_CALL_IMM once is OK for me. but I don't think the else branch is
unnecessary and it make the code
ugly. Can we just return directly when found that imm is overflowed ?

        call_imm = BPF_CALL_IMM(addr);
        /* Check whether or not the relative offset overflows desc->imm */
        if ((unsigned long)(s32)call_imm != call_imm) {
                verbose(env, "address of kernel function %s is out of range\n",
                        func_name);
                return -EINVAL;
        }

        desc = &tab->descs[tab->nr_descs++];
        desc->func_id = func_id;
        desc->imm = call_imm;




> .



^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH bpf-next v2] bpf: reject kfunc calls that overflow insn->imm
  2022-02-09  6:20   ` Hou Tao
@ 2022-02-09 15:31     ` Yonghong Song
  0 siblings, 0 replies; 4+ messages in thread
From: Yonghong Song @ 2022-02-09 15:31 UTC (permalink / raw)
  To: Hou Tao, Alexei Starovoitov
  Cc: Martin KaFai Lau, Daniel Borkmann, Andrii Nakryiko, Song Liu,
	John Fastabend, netdev, bpf



On 2/8/22 10:20 PM, Hou Tao wrote:
> Hi,
> 
> On 2/9/2022 12:57 AM, Yonghong Song wrote:
>>
>>
>> On 2/8/22 4:33 AM, Hou Tao wrote:
>>> Now kfunc call uses s32 to represent the offset between the address
>>> of kfunc and __bpf_call_base, but it doesn't check whether or not
>>> s32 will be overflowed, so add an extra checking to reject these
>>> invalid kfunc calls.
>>>
>>> Signed-off-by: Hou Tao <houtao1@huawei.com>
>>> ---
>>> v2:
>>>    * instead of checking the overflow in selftests, just reject
>>>      these kfunc calls directly in verifier
>>>
>>> v1: https://lore.kernel.org/bpf/20220206043107.18549-1-houtao1@huawei.com
>>> ---
>>>    kernel/bpf/verifier.c | 13 +++++++++++++
>>>    1 file changed, 13 insertions(+)
>>>
>>> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
>>> index a39eedecc93a..fd836e64b701 100644
>>> --- a/kernel/bpf/verifier.c
>>> +++ b/kernel/bpf/verifier.c
>>> @@ -1832,6 +1832,13 @@ static struct btf *find_kfunc_desc_btf(struct
>>> bpf_verifier_env *env,
>>>        return btf_vmlinux ?: ERR_PTR(-ENOENT);
>>>    }
>>>    +static inline bool is_kfunc_call_imm_overflowed(unsigned long addr)
>>> +{
>>> +    unsigned long offset = BPF_CALL_IMM(addr);
>>> +
>>> +    return (unsigned long)(s32)offset != offset;
>>> +}
>>> +
>>>    static int add_kfunc_call(struct bpf_verifier_env *env, u32 func_id, s16
>>> offset)
>>>    {
>>>        const struct btf_type *func, *func_proto;
>>> @@ -1925,6 +1932,12 @@ static int add_kfunc_call(struct bpf_verifier_env
>>> *env, u32 func_id, s16 offset)
>>>            return -EINVAL;
>>>        }
>>>    +    if (is_kfunc_call_imm_overflowed(addr)) {
>>> +        verbose(env, "address of kernel function %s is out of range\n",
>>> +            func_name);
>>> +        return -EINVAL;
>>> +    }
>>> +
>>>        desc = &tab->descs[tab->nr_descs++];
>>>        desc->func_id = func_id;
>>>        desc->imm = BPF_CALL_IMM(addr);
>>
>> Thanks, I would like to call BPF_CALL_IMM only once and keep checking overflow
>> and setting desc->imm close to each other. How about the following
>> not-compile-tested code
>>
>>      unsigned long call_imm;
>>
>>      ...
>>      call_imm = BPF_CALL_IMM(addr);
>>      /* some comment here */
>>      if ((unsigned long)(s32)call_imm != call_imm) {
>>          verbose(env, ...);
>>          return -EINVAL;
>>      } else {
>>          desc->imm = call_imm;
>>      }
> call BPF_CALL_IMM once is OK for me. but I don't think the else branch is
> unnecessary and it make the code
> ugly. Can we just return directly when found that imm is overflowed ?
> 
>          call_imm = BPF_CALL_IMM(addr);
>          /* Check whether or not the relative offset overflows desc->imm */
>          if ((unsigned long)(s32)call_imm != call_imm) {
>                  verbose(env, "address of kernel function %s is out of range\n",
>                          func_name);
>                  return -EINVAL;
>          }
> 
>          desc = &tab->descs[tab->nr_descs++];
>          desc->func_id = func_id;
>          desc->imm = call_imm;

Sure. Your above change looks good. My change is just
an illustration :-).

> 
> 
> 
> 
>> .
> 
> 

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2022-02-09 15:31 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-02-08 12:33 [PATCH bpf-next v2] bpf: reject kfunc calls that overflow insn->imm Hou Tao
2022-02-08 16:57 ` Yonghong Song
2022-02-09  6:20   ` Hou Tao
2022-02-09 15:31     ` Yonghong Song

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.