On 12/18/20 9:46 PM, Flavio Leitner wrote:
> On Fri, Dec 18, 2020 at 06:49:30PM +0100, Ilya Maximets wrote:
>> On 12/17/20 6:53 PM, Flavio Leitner wrote:
>>> On Thu, Dec 17, 2020 at 01:00:56PM +0100, Ilya Maximets wrote:
>>>> On 11/23/20 3:12 PM, Ilya Maximets wrote:
>>>>> Too big userdata could overflow netlink message leading to out-of-bound
>>>>> memory accesses or assertion while formatting nested actions.
>>>>>
>>>>> Fix that by checking the saize and returning correct error code.
>>> ^^^^^
>>> typo
>>>
>>>>>
>>>>> Credit to OSS-Fuzz.
>>>>>
>>>>> Reported-at: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=27640
>>>>> Fixes: e995e3df57ea ("Allow OVS_USERSPACE_ATTR_USERDATA to be variable
>>>>> length.")
>>>>> Signed-off-by: Ilya Maximets <[email protected]>
>>>>> ---
>>>>
>>>> Any thoughts on this?
>>>> This change should resove several issues reported by oss-fuzz.
>>>>
>>>> Best regards, Ilya Maximets.
>>>>
>>>>> lib/odp-util.c | 30 +++++++++++++++++++++--------
>>>>> lib/odp-util.h | 10 +++++-----
>>>>> ofproto/ofproto-dpif-xlate.c | 12 ++++++------
>>>>> tests/odp.at | 37 ++++++++++++++++++++++++++++++++++++
>>>>> 4 files changed, 70 insertions(+), 19 deletions(-)
>>>>>
>>>>> diff --git a/lib/odp-util.c b/lib/odp-util.c
>>>>> index 252a91bfa..879dea97e 100644
>>>>> --- a/lib/odp-util.c
>>>>> +++ b/lib/odp-util.c
>>>>> @@ -1455,14 +1455,20 @@ parse_odp_userspace_action(const char *s, struct
>>>>> ofpbuf *actions)
>>>>> int n1 = -1;
>>>>> if (ovs_scan(&s[n], ",tunnel_out_port=%"SCNi32")%n",
>>>>> &tunnel_out_port, &n1)) {
>>>>> - odp_put_userspace_action(pid, user_data, user_data_size,
>>>>> - tunnel_out_port, include_actions,
>>>>> actions);
>>>>> - res = n + n1;
>>>>> + res = odp_put_userspace_action(pid, user_data,
>>>>> user_data_size,
>>>>> + tunnel_out_port,
>>>>> include_actions,
>>>>> + actions);
>>>>> + if (res >= 0) {
>>>>> + res = n + n1;
>>>>> + }
>>>>> goto out;
>>>>> } else if (s[n] == ')') {
>>>>> - odp_put_userspace_action(pid, user_data, user_data_size,
>>>>> - ODPP_NONE, include_actions,
>>>>> actions);
>>>>> - res = n + 1;
>>>>> + res = odp_put_userspace_action(pid, user_data,
>>>>> user_data_size,
>>>>> + ODPP_NONE, include_actions,
>>>>> + actions);
>>>>> + if (res >= 0) {
>>>>> + res = n + 1;
>>>>> + }
>>>>> goto out;
>>>>> }
>>>>> }
>>>>> @@ -7559,8 +7565,10 @@ odp_key_fitness_to_string(enum odp_key_fitness
>>>>> fitness)
>>>>> * Netlink PID 'pid'. If 'userdata' is nonnull, adds a userdata
>>>>> attribute
>>>>> * whose contents are the 'userdata_size' bytes at 'userdata' and
>>>>> returns the
>>>>> * offset within 'odp_actions' of the start of the cookie. (If
>>>>> 'userdata' is
>>>>> - * null, then the return value is not meaningful.) */
>>>>> -size_t
>>>>> + * null, then the return value is not meaningful.)
>>>>> + *
>>>>> + * Returns negative error code on failure. */
>>>>> +int
>>>
>>> The type 'size_t' is 8 bytes while 'int' is 4 bytes and this function
>>> is returning 'size_t'. Later 'cookie_offset' is changed to use
>>> 'ssize_t' which then becomes 'size_t' again.
>>>
>>> Perhaps it would be cleaner if function returns 'int' as 0 if success
>>> or negative on error and optionally provide the offset as an size_t
>>> pointer passed as argument when that is required?
>>
>> I started do that, but all other functions in odp-util.c that calls this
>> one are using int as their type and converts size_t to int everywhere.
>> OTOH, most of functions in ofproto-dpif-xlate.c are using size_t, but
>> at the same time, some of them receives int from odp-util and converts
>> them to size_t unconditionally. This will be much bigger change over
>> the codebase in order to clean all of this up.
>
> Could you give one example? I am not seeing the problem.
> Just to be sure we are on the same page, I am proposing the
> following change on top of yours:
Oh. Thanks for the example. Now I see what is your idea here.
I missed the fact that we're not using the result of odp_put_userspace_action()
inside parse_odp_userspace_action(). With that I thought that we will need
to change the type of the 'res' variable and all the way up through the stack.
But that is not the case. I see it now.
For the change below, I'll incorporate it, but I'd rather not introduce
extra function. I think, It'll be fine if we'll just add an argument to
the existing one.
>
> diff --git a/lib/odp-util.c b/lib/odp-util.c
> index 879dea97e..c09827844 100644
> --- a/lib/odp-util.c
> +++ b/lib/odp-util.c
> @@ -1458,7 +1458,7 @@ parse_odp_userspace_action(const char *s, struct ofpbuf
> *actions)
> res = odp_put_userspace_action(pid, user_data, user_data_size,
> tunnel_out_port, include_actions,
> actions);
> - if (res >= 0) {
> + if (!res) {
> res = n + n1;
> }
> goto out;
> @@ -1466,7 +1466,7 @@ parse_odp_userspace_action(const char *s, struct ofpbuf
> *actions)
> res = odp_put_userspace_action(pid, user_data, user_data_size,
> ODPP_NONE, include_actions,
> actions);
> - if (res >= 0) {
> + if (!res) {
> res = n + 1;
> }
> goto out;
> @@ -7563,17 +7563,19 @@ odp_key_fitness_to_string(enum odp_key_fitness
> fitness)
>
> /* Appends an OVS_ACTION_ATTR_USERSPACE action to 'odp_actions' that
> specifies
> * Netlink PID 'pid'. If 'userdata' is nonnull, adds a userdata attribute
> - * whose contents are the 'userdata_size' bytes at 'userdata' and returns the
> - * offset within 'odp_actions' of the start of the cookie. (If 'userdata' is
> - * null, then the return value is not meaningful.)
> + * whose contents are the 'userdata_size' bytes at 'userdata' and sets
> + * 'odp_actions_ofs' if nonnull with the offset within 'odp_actions' of the
> + * start of the cookie. (If 'userdata' is null, then the 'odp_actions_ofs'
> + * value is not meaningful.)
> *
> * Returns negative error code on failure. */
> int
> -odp_put_userspace_action(uint32_t pid,
> - const void *userdata, size_t userdata_size,
> - odp_port_t tunnel_out_port,
> - bool include_actions,
> - struct ofpbuf *odp_actions)
> +odp_put_userspace_action_ofs(uint32_t pid,
> + const void *userdata, size_t userdata_size,
> + odp_port_t tunnel_out_port,
> + bool include_actions,
> + struct ofpbuf *odp_actions,
> + size_t *odp_actions_ofs)
> {
> size_t userdata_ofs;
> size_t offset;
> @@ -7614,7 +7616,28 @@ odp_put_userspace_action(uint32_t pid,
> }
> nl_msg_end_nested(odp_actions, offset);
>
> - return userdata_ofs;
> + if (odp_actions_ofs) {
> + *odp_actions_ofs = userdata_ofs;
> + }
> +
> + return 0;
> +}
> +
> +/* Appends an OVS_ACTION_ATTR_USERSPACE action to 'odp_actions' that
> specifies
> + * Netlink PID 'pid'. If 'userdata' is nonnull, adds a userdata attribute
> + * whose contents are the 'userdata_size' bytes at 'userdata'.
> + *
> + * Returns negative error code on failure. */
> +int
> +odp_put_userspace_action(uint32_t pid,
> + const void *userdata, size_t userdata_size,
> + odp_port_t tunnel_out_port,
> + bool include_actions,
> + struct ofpbuf *odp_actions)
> +{
> + return odp_put_userspace_action_ofs(pid, userdata, userdata_size,
> + tunnel_out_port, include_actions,
> + odp_actions, NULL);
> }
>
> void
> diff --git a/lib/odp-util.h b/lib/odp-util.h
> index 46593c411..a53f2a512 100644
> --- a/lib/odp-util.h
> +++ b/lib/odp-util.h
> @@ -361,6 +361,12 @@ int odp_put_userspace_action(uint32_t pid,
> odp_port_t tunnel_out_port,
> bool include_actions,
> struct ofpbuf *odp_actions);
> +int odp_put_userspace_action_ofs(uint32_t pid,
> + const void *userdata, size_t userdata_size,
> + odp_port_t tunnel_out_port,
> + bool include_actions,
> + struct ofpbuf *odp_actions,
> + size_t *odp_actions_ofs);
> void odp_put_tunnel_action(const struct flow_tnl *tunnel,
> struct ofpbuf *odp_actions,
> const char *tnl_type);
> diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
> index 9171290e0..64fca6e7a 100644
> --- a/ofproto/ofproto-dpif-xlate.c
> +++ b/ofproto/ofproto-dpif-xlate.c
> @@ -3222,12 +3222,11 @@ compose_sample_action(struct xlate_ctx *ctx,
> odp_port_t odp_port = ofp_port_to_odp_port(
> ctx->xbridge, ctx->xin->flow.in_port.ofp_port);
> uint32_t pid = dpif_port_get_pid(ctx->xbridge->dpif, odp_port);
> - ssize_t cookie_offset = odp_put_userspace_action(pid, cookie,
> - sizeof *cookie,
> - tunnel_out_port,
> - include_actions,
> - ctx->odp_actions);
> - ovs_assert(cookie_offset >= 0);
> + size_t cookie_offset;
> + int ret = odp_put_userspace_action_ofs(pid, cookie, sizeof *cookie,
> + tunnel_out_port, include_actions,
> + ctx->odp_actions, &cookie_offset);
> + ovs_assert(ret == 0);
> if (is_sample) {
> nl_msg_end_nested(ctx->odp_actions, actions_offset);
> nl_msg_end_nested(ctx->odp_actions, sample_offset);
>
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev