Re: [PATCH] NFS: fix nfs_parse_ip_address() corner case

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

 



On Thu, Sep 4, 2008 at 4:23 PM, J. Bruce Fields <bfields@xxxxxxxxxxxx> wrote:
> On Wed, Sep 03, 2008 at 04:35:57PM -0400, Chuck Lever wrote:
>> Bruce observed that nfs_parse_ip_address() will successfully parse an
>> IPv6 address that looks like this:
>>
>>   "::1%"
>>
>> A scope delimiter is present, but there is no scope ID following it.
>> This is harmless, as it would simply set the scope ID to zero.  However,
>> in some cases we would like to flag this as an improperly formed
>> address.
>>
>> We are now also careful to reject addresses where garbage follows the
>> address (up to the length of the string), instead of ignoring the
>> non-address characters; and where the scope ID is nonsense (not a valid
>> device name, but also not numeric).  Before, both of these cases would
>> result in a harmless zero scope ID.
>
> Slightly irrelevant, but same comment as before--wouldn't it be easier
> to follow the logic if instead of:
>
>        p = kstrndup(...)
>        if (p) {
>                do stuff for successful case
>                ....
>                return 1;
>        }
>
>        return 0;
>
> it were:
>
>        p = kstrndup(...)
>        if (!p)
>                return 0;
>        do stuff for successful case
>        ...
>        return 1;

I tried that.  It made this patch about 3x larger than it needed to
be, obscured the changes introduced by the patch, and made it harder
to show that the new logic is correct.  As we are not introducing new
code here but repairing existing issues, such a clean up would need to
be in a separate patch.

I generally prefer to use a structured language as it was intended,
rather than to abuse "goto" as is the trend in the Linux kernel.  By
creating named subroutines instead of using lambda functions and using
brackets creatively and intelligently, we codify the assumptions and
architecture of a set of tasks without excessive comments.  This also
limits the scope of automatic variables and keeps each function nearly
as simple as possible, making the code more robust in the face of
changes over time by multiple forgetful developers.

In addition, using positive instead of negative logic groups the
"success" path together into a few lines rather than spreading it out
over the whole function.  Writing this way is a style preference;
Knuth (?) and others make an argument in favor of it.  Often this is a
good way to ensure error handling is correct (eg memory allocations
are guaranteed to be properly freed in every error case because the
structuring forces it).

C suffers from a lack of proper exception handling constructs, which
would help readability and correct error case handling.  But these
functions are small enough that writing them using structured precepts
is simple enough and doesn't have a strong negative effect on
readability.

Also, the C compiler assumes the "if" expression will evaluate to TRUE
more often than FALSE so it arranges the branch instructions so that
the CPU's branch prediction logic will work more efficiently.  Not
really critical in this particular case.

Finally when practical I try to use a single exit/return point to
reduce code duplication and to arrange the code in advance for easier
debugging, though sometimes that obfuscates.

Though I am not always consistent on these points, I don't see a
strong need to re-arrange as you suggest in this case.

>
> e.g., the below, on top of yours. (Untested.)
>
> Might also combine the two final exits in the usual way:
>
>        out:
>                kfree(p);
>                return ret;
>
> --b.
>
> diff --git a/fs/nfs/super.c b/fs/nfs/super.c
> index a9f5a12..fcee897 100644
> --- a/fs/nfs/super.c
> +++ b/fs/nfs/super.c
> @@ -733,6 +733,8 @@ static int nfs_parse_ipv6_scope_id(const char *string, const size_t str_len,
>  {
>        size_t len = (string + str_len) - delim - 1;
>        char *p;
> +       unsigned long scope_id = 0;
> +       struct net_device *dev;
>
>        if (len == 0)
>                return 1;
> @@ -744,29 +746,25 @@ static int nfs_parse_ipv6_scope_id(const char *string, const size_t str_len,
>                return 0;
>
>        p = kstrndup(delim + 1, len, GFP_KERNEL);
> -       if (p) {
> -               unsigned long scope_id = 0;
> -               struct net_device *dev;
> -
> -               dev = dev_get_by_name(&init_net, p);
> -               if (dev != NULL) {
> -                       scope_id = dev->ifindex;
> -                       dev_put(dev);
> -               } else {
> -                       if (strict_strtoul(p, 10, &scope_id) == 0) {
> -                               kfree(p);
> -                               return 0;
> -                       }
> -               }
> -
> -               kfree(p);
> +       if (!p)
> +               return 0;
>
> -               sin6->sin6_scope_id = scope_id;
> -               dfprintk(MOUNT, "NFS: IPv6 scope ID = %lu\n", scope_id);
> -               return 1;
> +       dev = dev_get_by_name(&init_net, p);
> +       if (dev != NULL) {
> +               scope_id = dev->ifindex;
> +               dev_put(dev);
> +       } else {
> +               if (strict_strtoul(p, 10, &scope_id) == 0) {
> +                       kfree(p);
> +                       return 0;
> +               }
>        }
>
> -       return 0;
> +       kfree(p);
> +
> +       sin6->sin6_scope_id = scope_id;
> +       dfprintk(MOUNT, "NFS: IPv6 scope ID = %lu\n", scope_id);
> +       return 1;
>  }
>
>  static void nfs_parse_ipv6_address(char *string, size_t str_len,
> --
> To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
> the body of a message to majordomo@xxxxxxxxxxxxxxx
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>



-- 
"If you simplify your English, you are freed from the worst follies of
orthodoxy."
 -- George Orwell
--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Filesystem Development]     [Linux USB Development]     [Linux Media Development]     [Video for Linux]     [Linux NILFS]     [Linux Audio Users]     [Yosemite Info]     [Linux SCSI]

  Powered by Linux