qemu-trivial
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH 1/2] linux-user: add do_setsockopt SOL_CAN_RAW CAN_RAW_FILTER


From: Laurent Vivier
Subject: Re: [PATCH 1/2] linux-user: add do_setsockopt SOL_CAN_RAW CAN_RAW_FILTER support
Date: Tue, 12 May 2020 22:09:01 +0200
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Thunderbird/68.7.0

Le 06/05/2020 à 15:21, Tomas Krcka a écrit :
> Signed-off-by: Tomas Krcka <address@hidden>
> ---
>  linux-user/syscall.c | 34 ++++++++++++++++++++++++++++++++++
>  1 file changed, 34 insertions(+)
> 
> diff --git a/linux-user/syscall.c b/linux-user/syscall.c
> index 05f03919ff..88d4c85b70 100644
> --- a/linux-user/syscall.c
> +++ b/linux-user/syscall.c
> @@ -56,6 +56,7 @@
>  #include <linux/wireless.h>
>  #include <linux/icmp.h>
>  #include <linux/icmpv6.h>
> +#include <linux/can/raw.h>
>  #include <linux/errqueue.h>
>  #include <linux/random.h>
>  #ifdef CONFIG_TIMERFD
> @@ -2111,6 +2112,39 @@ static abi_long do_setsockopt(int sockfd, int level, 
> int optname,
>              goto unimplemented;
>          }
>          break;
> +    case SOL_CAN_RAW:
> +        switch (optname) {
> +        case CAN_RAW_FILTER:
> +        {
> +            if (optlen % sizeof(struct can_filter) != 0) {
> +                return -TARGET_EINVAL;
> +            }
> +
> +            struct can_filter  *can_filters = NULL;

Move the declaration to the top of the block.

> +            if (optlen != 0) {

If you check, like in kernel, "optlen > CAN_RAW_FILTER_MAX *
sizeof(struct can_filter)", you can exit here (and no need to set
can_filters to NULL).

> +                can_filters = g_new0(struct can_filter, optlen);
> +
> +                if (!can_filters) {

no need to check the result, g_new0() aborts in case of problem.

> +                    return -TARGET_ENOMEM;
> +                }
> +                if (copy_from_user(can_filters, optval_addr, optlen)) {
> +                    g_free(can_filters);
> +                    return -TARGET_EFAULT;
> +                }

It would be cleaner not to use the copy_from_user() as we need to
byte-swap all the fields in the loop below (I know it's done like that
in SOL_ICMPV6...)

> +                for (val = 0; val < optlen / sizeof(struct can_filter); 
> val++) {
> +                    can_filters[val].can_id = 
> tswap32(can_filters[val].can_id);
> +                    can_filters[val].can_mask = 
> tswap32(can_filters[val].can_mask);
> +                }

So, something like:

target_can_filters = lock_user(VERIFY_READ, optval_addr, optlen, 1);
for (val = 0; val < optlen / sizeof(struct can_filter); val++) {
    __get_user(can_filters[val].can_id, \
               &target_can_filters[val].can_id);
    __get_user(can_filters[val].can_mask, \
               &target_can_filters[val].can_mask);
}
unlock_user(target_can_filters);

> +            }
> +            ret = get_errno(setsockopt(sockfd, level, optname,
> +                                        can_filters, optlen));
> +            g_free(can_filters);
> +            break;
> +        }
> +        default:
> +            goto unimplemented;
> +        }
> +        break;
>      case SOL_RAW:
>          switch (optname) {
>          case ICMP_FILTER:
> 

Could you also update getsockopt()?

Thanks,
Laurent





reply via email to

[Prev in Thread] Current Thread [Next in Thread]