Eric W. Biederman wrote:
>>+     if (linkinfo[IFLA_INFO_NAME]) {
>>+             nla_strlcpy(name, linkinfo[IFLA_INFO_NAME], sizeof(name));
>>+             ops = rtnl_link_ops_get(name);
> 
> 
> Ugh.  Shouldn't we have the request_module logic here?
> Otherwise it looks like we can skip the validate method and 
> have other weird interactions.


Good catch. The easiest solution seems be to simply replay the
request after successful module load, which also avoids the
device lookup race.

Something like this (untested).

diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 8d2f817..f2868b0 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -930,6 +930,7 @@ static int rtnl_newlink(struct sk_buff *skb, struct 
nlmsghdr *nlh, void *arg)
        struct nlattr *linkinfo[IFLA_INFO_MAX+1];
        int err;
 
+replay:
        err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy);
        if (err < 0)
                return err;
@@ -1012,19 +1013,19 @@ static int rtnl_newlink(struct sk_buff *skb, struct 
nlmsghdr *nlh, void *arg)
                if (tb[IFLA_ADDRESS] || tb[IFLA_BROADCAST] || tb[IFLA_MAP])
                        return -EOPNOTSUPP;
 
+               if (!ops) {
 #ifdef CONFIG_KMOD
-               if (!ops && kind[0]) {
-                       /* race condition: device may be created while rtnl is
-                        * unlocked, final register_netdevice will catch it.
-                        */
-                       __rtnl_unlock();
-                       request_module("rtnl-link-%s", kind);
-                       rtnl_lock();
-                       ops = rtnl_link_ops_get(kind);
-               }
+                       if (kind[0]) {
+                               __rtnl_unlock();
+                               request_module("rtnl-link-%s", kind);
+                               rtnl_lock();
+                               ops = rtnl_link_ops_get(kind);
+                               if (ops)
+                                       goto replay;
+                       }
 #endif
-               if (!ops)
                        return -EOPNOTSUPP;
+               }
 
                if (!ifname[0])
                        snprintf(ifname, IFNAMSIZ, "%s%%d", ops->kind);

Reply via email to