* [net-next:master 375/376] net/core/rtnetlink.c:3099:1: warning: the frame size of 1280 bytes is larger than 1024 bytes
From: kbuild test robot @ 2018-06-01 5:07 UTC (permalink / raw)
To: Kees Cook; +Cc: kbuild-all, netdev
[-- Attachment #1: Type: text/plain, Size: 18883 bytes --]
tree: https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git master
head: 4b8e6ac41a594ea67ded6af6af5935f03221ea4c
commit: ccf8dbcd062a930e64741c939ca784d15316aa0c [375/376] rtnetlink: Remove VLA usage
config: um-x86_64_defconfig (attached as .config)
compiler: gcc-7 (Debian 7.3.0-16) 7.3.0
reproduce:
git checkout ccf8dbcd062a930e64741c939ca784d15316aa0c
# save the attached .config to linux build tree
make ARCH=um SUBARCH=x86_64
All warnings (new ones prefixed by >>):
net/core/rtnetlink.c: In function 'rtnl_newlink':
>> net/core/rtnetlink.c:3099:1: warning: the frame size of 1280 bytes is larger than 1024 bytes [-Wframe-larger-than=]
}
^
vim +3099 net/core/rtnetlink.c
e7ed828f1 Vlad Dogaru 2011-01-13 2842
c21ef3e34 David Ahern 2017-04-16 2843 static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh,
c21ef3e34 David Ahern 2017-04-16 2844 struct netlink_ext_ack *extack)
38f7b870d Patrick McHardy 2007-06-13 2845 {
3b1e0a655 YOSHIFUJI Hideaki 2008-03-26 2846 struct net *net = sock_net(skb->sk);
38f7b870d Patrick McHardy 2007-06-13 2847 const struct rtnl_link_ops *ops;
ba7d49b1f Jiri Pirko 2014-01-22 2848 const struct rtnl_link_ops *m_ops = NULL;
38f7b870d Patrick McHardy 2007-06-13 2849 struct net_device *dev;
ba7d49b1f Jiri Pirko 2014-01-22 2850 struct net_device *master_dev = NULL;
38f7b870d Patrick McHardy 2007-06-13 2851 struct ifinfomsg *ifm;
38f7b870d Patrick McHardy 2007-06-13 2852 char kind[MODULE_NAME_LEN];
38f7b870d Patrick McHardy 2007-06-13 2853 char ifname[IFNAMSIZ];
38f7b870d Patrick McHardy 2007-06-13 2854 struct nlattr *tb[IFLA_MAX+1];
38f7b870d Patrick McHardy 2007-06-13 2855 struct nlattr *linkinfo[IFLA_INFO_MAX+1];
5517750f0 Tom Gundersen 2014-07-14 2856 unsigned char name_assign_type = NET_NAME_USER;
38f7b870d Patrick McHardy 2007-06-13 2857 int err;
38f7b870d Patrick McHardy 2007-06-13 2858
95a5afca4 Johannes Berg 2008-10-16 2859 #ifdef CONFIG_MODULES
38f7b870d Patrick McHardy 2007-06-13 2860 replay:
8072f085d Thomas Graf 2007-07-31 2861 #endif
c21ef3e34 David Ahern 2017-04-16 2862 err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy, extack);
38f7b870d Patrick McHardy 2007-06-13 2863 if (err < 0)
38f7b870d Patrick McHardy 2007-06-13 2864 return err;
38f7b870d Patrick McHardy 2007-06-13 2865
4ff66cae7 Christian Brauner 2018-02-07 2866 err = rtnl_ensure_unique_netns(tb, extack, false);
4ff66cae7 Christian Brauner 2018-02-07 2867 if (err < 0)
4ff66cae7 Christian Brauner 2018-02-07 2868 return err;
4ff66cae7 Christian Brauner 2018-02-07 2869
38f7b870d Patrick McHardy 2007-06-13 2870 if (tb[IFLA_IFNAME])
38f7b870d Patrick McHardy 2007-06-13 2871 nla_strlcpy(ifname, tb[IFLA_IFNAME], IFNAMSIZ);
38f7b870d Patrick McHardy 2007-06-13 2872 else
38f7b870d Patrick McHardy 2007-06-13 2873 ifname[0] = '\0';
38f7b870d Patrick McHardy 2007-06-13 2874
38f7b870d Patrick McHardy 2007-06-13 2875 ifm = nlmsg_data(nlh);
38f7b870d Patrick McHardy 2007-06-13 2876 if (ifm->ifi_index > 0)
881d966b4 Eric W. Biederman 2007-09-17 2877 dev = __dev_get_by_index(net, ifm->ifi_index);
e7ed828f1 Vlad Dogaru 2011-01-13 2878 else {
e7ed828f1 Vlad Dogaru 2011-01-13 2879 if (ifname[0])
881d966b4 Eric W. Biederman 2007-09-17 2880 dev = __dev_get_by_name(net, ifname);
38f7b870d Patrick McHardy 2007-06-13 2881 else
38f7b870d Patrick McHardy 2007-06-13 2882 dev = NULL;
e7ed828f1 Vlad Dogaru 2011-01-13 2883 }
38f7b870d Patrick McHardy 2007-06-13 2884
ba7d49b1f Jiri Pirko 2014-01-22 2885 if (dev) {
ba7d49b1f Jiri Pirko 2014-01-22 2886 master_dev = netdev_master_upper_dev_get(dev);
ba7d49b1f Jiri Pirko 2014-01-22 2887 if (master_dev)
ba7d49b1f Jiri Pirko 2014-01-22 2888 m_ops = master_dev->rtnl_link_ops;
ba7d49b1f Jiri Pirko 2014-01-22 2889 }
ba7d49b1f Jiri Pirko 2014-01-22 2890
e0d087af7 Eric Dumazet 2009-11-07 2891 err = validate_linkmsg(dev, tb);
e0d087af7 Eric Dumazet 2009-11-07 2892 if (err < 0)
1840bb13c Thomas Graf 2008-02-23 2893 return err;
1840bb13c Thomas Graf 2008-02-23 2894
38f7b870d Patrick McHardy 2007-06-13 2895 if (tb[IFLA_LINKINFO]) {
38f7b870d Patrick McHardy 2007-06-13 2896 err = nla_parse_nested(linkinfo, IFLA_INFO_MAX,
fceb6435e Johannes Berg 2017-04-12 2897 tb[IFLA_LINKINFO], ifla_info_policy,
fceb6435e Johannes Berg 2017-04-12 2898 NULL);
38f7b870d Patrick McHardy 2007-06-13 2899 if (err < 0)
38f7b870d Patrick McHardy 2007-06-13 2900 return err;
38f7b870d Patrick McHardy 2007-06-13 2901 } else
38f7b870d Patrick McHardy 2007-06-13 2902 memset(linkinfo, 0, sizeof(linkinfo));
38f7b870d Patrick McHardy 2007-06-13 2903
38f7b870d Patrick McHardy 2007-06-13 2904 if (linkinfo[IFLA_INFO_KIND]) {
38f7b870d Patrick McHardy 2007-06-13 2905 nla_strlcpy(kind, linkinfo[IFLA_INFO_KIND], sizeof(kind));
38f7b870d Patrick McHardy 2007-06-13 2906 ops = rtnl_link_ops_get(kind);
38f7b870d Patrick McHardy 2007-06-13 2907 } else {
38f7b870d Patrick McHardy 2007-06-13 2908 kind[0] = '\0';
38f7b870d Patrick McHardy 2007-06-13 2909 ops = NULL;
38f7b870d Patrick McHardy 2007-06-13 2910 }
38f7b870d Patrick McHardy 2007-06-13 2911
38f7b870d Patrick McHardy 2007-06-13 2912 if (1) {
ccf8dbcd0 Kees Cook 2018-05-30 2913 struct nlattr *attr[RTNL_MAX_TYPE + 1];
ccf8dbcd0 Kees Cook 2018-05-30 2914 struct nlattr *slave_attr[RTNL_SLAVE_MAX_TYPE + 1];
ba7d49b1f Jiri Pirko 2014-01-22 2915 struct nlattr **data = NULL;
ba7d49b1f Jiri Pirko 2014-01-22 2916 struct nlattr **slave_data = NULL;
317f4810e Nicolas Dichtel 2015-01-15 2917 struct net *dest_net, *link_net = NULL;
38f7b870d Patrick McHardy 2007-06-13 2918
38f7b870d Patrick McHardy 2007-06-13 2919 if (ops) {
ccf8dbcd0 Kees Cook 2018-05-30 2920 if (ops->maxtype > RTNL_MAX_TYPE)
ccf8dbcd0 Kees Cook 2018-05-30 2921 return -EINVAL;
ccf8dbcd0 Kees Cook 2018-05-30 2922
38f7b870d Patrick McHardy 2007-06-13 2923 if (ops->maxtype && linkinfo[IFLA_INFO_DATA]) {
38f7b870d Patrick McHardy 2007-06-13 2924 err = nla_parse_nested(attr, ops->maxtype,
38f7b870d Patrick McHardy 2007-06-13 2925 linkinfo[IFLA_INFO_DATA],
fceb6435e Johannes Berg 2017-04-12 2926 ops->policy, NULL);
38f7b870d Patrick McHardy 2007-06-13 2927 if (err < 0)
38f7b870d Patrick McHardy 2007-06-13 2928 return err;
38f7b870d Patrick McHardy 2007-06-13 2929 data = attr;
38f7b870d Patrick McHardy 2007-06-13 2930 }
38f7b870d Patrick McHardy 2007-06-13 2931 if (ops->validate) {
a8b8a889e Matthias Schiffer 2017-06-25 2932 err = ops->validate(tb, data, extack);
38f7b870d Patrick McHardy 2007-06-13 2933 if (err < 0)
38f7b870d Patrick McHardy 2007-06-13 2934 return err;
38f7b870d Patrick McHardy 2007-06-13 2935 }
38f7b870d Patrick McHardy 2007-06-13 2936 }
38f7b870d Patrick McHardy 2007-06-13 2937
ba7d49b1f Jiri Pirko 2014-01-22 2938 if (m_ops) {
ccf8dbcd0 Kees Cook 2018-05-30 2939 if (ops->slave_maxtype > RTNL_SLAVE_MAX_TYPE)
ccf8dbcd0 Kees Cook 2018-05-30 2940 return -EINVAL;
ccf8dbcd0 Kees Cook 2018-05-30 2941
ba7d49b1f Jiri Pirko 2014-01-22 2942 if (m_ops->slave_maxtype &&
ba7d49b1f Jiri Pirko 2014-01-22 2943 linkinfo[IFLA_INFO_SLAVE_DATA]) {
ba7d49b1f Jiri Pirko 2014-01-22 2944 err = nla_parse_nested(slave_attr,
ba7d49b1f Jiri Pirko 2014-01-22 2945 m_ops->slave_maxtype,
ba7d49b1f Jiri Pirko 2014-01-22 2946 linkinfo[IFLA_INFO_SLAVE_DATA],
fceb6435e Johannes Berg 2017-04-12 2947 m_ops->slave_policy,
fceb6435e Johannes Berg 2017-04-12 2948 NULL);
ba7d49b1f Jiri Pirko 2014-01-22 2949 if (err < 0)
ba7d49b1f Jiri Pirko 2014-01-22 2950 return err;
ba7d49b1f Jiri Pirko 2014-01-22 2951 slave_data = slave_attr;
ba7d49b1f Jiri Pirko 2014-01-22 2952 }
ba7d49b1f Jiri Pirko 2014-01-22 2953 }
ba7d49b1f Jiri Pirko 2014-01-22 2954
38f7b870d Patrick McHardy 2007-06-13 2955 if (dev) {
90c325e3b Nicolas Dichtel 2014-09-01 2956 int status = 0;
38f7b870d Patrick McHardy 2007-06-13 2957
38f7b870d Patrick McHardy 2007-06-13 2958 if (nlh->nlmsg_flags & NLM_F_EXCL)
38f7b870d Patrick McHardy 2007-06-13 2959 return -EEXIST;
38f7b870d Patrick McHardy 2007-06-13 2960 if (nlh->nlmsg_flags & NLM_F_REPLACE)
38f7b870d Patrick McHardy 2007-06-13 2961 return -EOPNOTSUPP;
38f7b870d Patrick McHardy 2007-06-13 2962
38f7b870d Patrick McHardy 2007-06-13 2963 if (linkinfo[IFLA_INFO_DATA]) {
38f7b870d Patrick McHardy 2007-06-13 2964 if (!ops || ops != dev->rtnl_link_ops ||
38f7b870d Patrick McHardy 2007-06-13 2965 !ops->changelink)
38f7b870d Patrick McHardy 2007-06-13 2966 return -EOPNOTSUPP;
38f7b870d Patrick McHardy 2007-06-13 2967
ad744b223 Matthias Schiffer 2017-06-25 2968 err = ops->changelink(dev, tb, data, extack);
38f7b870d Patrick McHardy 2007-06-13 2969 if (err < 0)
38f7b870d Patrick McHardy 2007-06-13 2970 return err;
ba9989069 Nicolas Dichtel 2014-09-01 2971 status |= DO_SETLINK_NOTIFY;
38f7b870d Patrick McHardy 2007-06-13 2972 }
38f7b870d Patrick McHardy 2007-06-13 2973
ba7d49b1f Jiri Pirko 2014-01-22 2974 if (linkinfo[IFLA_INFO_SLAVE_DATA]) {
ba7d49b1f Jiri Pirko 2014-01-22 2975 if (!m_ops || !m_ops->slave_changelink)
ba7d49b1f Jiri Pirko 2014-01-22 2976 return -EOPNOTSUPP;
ba7d49b1f Jiri Pirko 2014-01-22 2977
ba7d49b1f Jiri Pirko 2014-01-22 2978 err = m_ops->slave_changelink(master_dev, dev,
17dd0ec47 Matthias Schiffer 2017-06-25 2979 tb, slave_data,
17dd0ec47 Matthias Schiffer 2017-06-25 2980 extack);
ba7d49b1f Jiri Pirko 2014-01-22 2981 if (err < 0)
ba7d49b1f Jiri Pirko 2014-01-22 2982 return err;
ba9989069 Nicolas Dichtel 2014-09-01 2983 status |= DO_SETLINK_NOTIFY;
ba7d49b1f Jiri Pirko 2014-01-22 2984 }
ba7d49b1f Jiri Pirko 2014-01-22 2985
ddf9f9707 Jakub Kicinski 2017-04-30 2986 return do_setlink(skb, dev, ifm, extack, tb, ifname,
ddf9f9707 Jakub Kicinski 2017-04-30 2987 status);
38f7b870d Patrick McHardy 2007-06-13 2988 }
38f7b870d Patrick McHardy 2007-06-13 2989
ffa934f19 Patrick McHardy 2011-01-20 2990 if (!(nlh->nlmsg_flags & NLM_F_CREATE)) {
ffa934f19 Patrick McHardy 2011-01-20 2991 if (ifm->ifi_index == 0 && tb[IFLA_GROUP])
90f62cf30 Eric W. Biederman 2014-04-23 2992 return rtnl_group_changelink(skb, net,
ffa934f19 Patrick McHardy 2011-01-20 2993 nla_get_u32(tb[IFLA_GROUP]),
ddf9f9707 Jakub Kicinski 2017-04-30 2994 ifm, extack, tb);
38f7b870d Patrick McHardy 2007-06-13 2995 return -ENODEV;
ffa934f19 Patrick McHardy 2011-01-20 2996 }
38f7b870d Patrick McHardy 2007-06-13 2997
160ca0142 Theuns Verwoerd 2017-01-31 2998 if (tb[IFLA_MAP] || tb[IFLA_PROTINFO])
38f7b870d Patrick McHardy 2007-06-13 2999 return -EOPNOTSUPP;
38f7b870d Patrick McHardy 2007-06-13 3000
38f7b870d Patrick McHardy 2007-06-13 3001 if (!ops) {
95a5afca4 Johannes Berg 2008-10-16 3002 #ifdef CONFIG_MODULES
38f7b870d Patrick McHardy 2007-06-13 3003 if (kind[0]) {
38f7b870d Patrick McHardy 2007-06-13 3004 __rtnl_unlock();
38f7b870d Patrick McHardy 2007-06-13 3005 request_module("rtnl-link-%s", kind);
38f7b870d Patrick McHardy 2007-06-13 3006 rtnl_lock();
38f7b870d Patrick McHardy 2007-06-13 3007 ops = rtnl_link_ops_get(kind);
38f7b870d Patrick McHardy 2007-06-13 3008 if (ops)
38f7b870d Patrick McHardy 2007-06-13 3009 goto replay;
38f7b870d Patrick McHardy 2007-06-13 3010 }
38f7b870d Patrick McHardy 2007-06-13 3011 #endif
38f7b870d Patrick McHardy 2007-06-13 3012 return -EOPNOTSUPP;
38f7b870d Patrick McHardy 2007-06-13 3013 }
38f7b870d Patrick McHardy 2007-06-13 3014
b0ab2fabb Jiri Pirko 2014-06-26 3015 if (!ops->setup)
b0ab2fabb Jiri Pirko 2014-06-26 3016 return -EOPNOTSUPP;
b0ab2fabb Jiri Pirko 2014-06-26 3017
5517750f0 Tom Gundersen 2014-07-14 3018 if (!ifname[0]) {
38f7b870d Patrick McHardy 2007-06-13 3019 snprintf(ifname, IFNAMSIZ, "%s%%d", ops->kind);
5517750f0 Tom Gundersen 2014-07-14 3020 name_assign_type = NET_NAME_ENUM;
5517750f0 Tom Gundersen 2014-07-14 3021 }
38f7b870d Patrick McHardy 2007-06-13 3022
5bb8ed075 Christian Brauner 2018-01-29 3023 dest_net = rtnl_link_get_net_capable(skb, net, tb, CAP_NET_ADMIN);
13ad17745 Eric W. Biederman 2011-01-29 3024 if (IS_ERR(dest_net))
13ad17745 Eric W. Biederman 2011-01-29 3025 return PTR_ERR(dest_net);
13ad17745 Eric W. Biederman 2011-01-29 3026
317f4810e Nicolas Dichtel 2015-01-15 3027 if (tb[IFLA_LINK_NETNSID]) {
317f4810e Nicolas Dichtel 2015-01-15 3028 int id = nla_get_s32(tb[IFLA_LINK_NETNSID]);
317f4810e Nicolas Dichtel 2015-01-15 3029
317f4810e Nicolas Dichtel 2015-01-15 3030 link_net = get_net_ns_by_id(dest_net, id);
317f4810e Nicolas Dichtel 2015-01-15 3031 if (!link_net) {
317f4810e Nicolas Dichtel 2015-01-15 3032 err = -EINVAL;
317f4810e Nicolas Dichtel 2015-01-15 3033 goto out;
317f4810e Nicolas Dichtel 2015-01-15 3034 }
06615bed6 Eric W. Biederman 2015-02-26 3035 err = -EPERM;
06615bed6 Eric W. Biederman 2015-02-26 3036 if (!netlink_ns_capable(skb, link_net->user_ns, CAP_NET_ADMIN))
06615bed6 Eric W. Biederman 2015-02-26 3037 goto out;
317f4810e Nicolas Dichtel 2015-01-15 3038 }
317f4810e Nicolas Dichtel 2015-01-15 3039
317f4810e Nicolas Dichtel 2015-01-15 3040 dev = rtnl_create_link(link_net ? : dest_net, ifname,
317f4810e Nicolas Dichtel 2015-01-15 3041 name_assign_type, ops, tb);
9c7dafbfa Pavel Emelyanov 2012-08-08 3042 if (IS_ERR(dev)) {
e71992889 Pavel Emelianov 2007-08-08 3043 err = PTR_ERR(dev);
9c7dafbfa Pavel Emelyanov 2012-08-08 3044 goto out;
9c7dafbfa Pavel Emelyanov 2012-08-08 3045 }
9c7dafbfa Pavel Emelyanov 2012-08-08 3046
9c7dafbfa Pavel Emelyanov 2012-08-08 3047 dev->ifindex = ifm->ifi_index;
9c7dafbfa Pavel Emelyanov 2012-08-08 3048
0e0eee246 Cong Wang 2014-02-11 3049 if (ops->newlink) {
7a3f4a185 Matthias Schiffer 2017-06-25 3050 err = ops->newlink(link_net ? : net, dev, tb, data,
7a3f4a185 Matthias Schiffer 2017-06-25 3051 extack);
0e0eee246 Cong Wang 2014-02-11 3052 /* Drivers should call free_netdev() in ->destructor
e51fb1523 Cong Wang 2014-06-03 3053 * and unregister it on failure after registration
e51fb1523 Cong Wang 2014-06-03 3054 * so that device could be finally freed in rtnl_unlock.
0e0eee246 Cong Wang 2014-02-11 3055 */
e51fb1523 Cong Wang 2014-06-03 3056 if (err < 0) {
e51fb1523 Cong Wang 2014-06-03 3057 /* If device is not registered at all, free it now */
e51fb1523 Cong Wang 2014-06-03 3058 if (dev->reg_state == NETREG_UNINITIALIZED)
e51fb1523 Cong Wang 2014-06-03 3059 free_netdev(dev);
0e0eee246 Cong Wang 2014-02-11 3060 goto out;
e51fb1523 Cong Wang 2014-06-03 3061 }
0e0eee246 Cong Wang 2014-02-11 3062 } else {
2d85cba2b Patrick McHardy 2007-07-11 3063 err = register_netdevice(dev);
fce9b9be8 Dan Carpenter 2013-08-14 3064 if (err < 0) {
38f7b870d Patrick McHardy 2007-06-13 3065 free_netdev(dev);
3729d5021 Patrick McHardy 2010-02-26 3066 goto out;
fce9b9be8 Dan Carpenter 2013-08-14 3067 }
0e0eee246 Cong Wang 2014-02-11 3068 }
3729d5021 Patrick McHardy 2010-02-26 3069 err = rtnl_configure_link(dev, ifm);
436389007 David S. Miller 2015-03-10 3070 if (err < 0)
436389007 David S. Miller 2015-03-10 3071 goto out_unregister;
bdef279b9 Nicolas Dichtel 2015-01-20 3072 if (link_net) {
317f4810e Nicolas Dichtel 2015-01-15 3073 err = dev_change_net_namespace(dev, dest_net, ifname);
bdef279b9 Nicolas Dichtel 2015-01-20 3074 if (err < 0)
436389007 David S. Miller 2015-03-10 3075 goto out_unregister;
bdef279b9 Nicolas Dichtel 2015-01-20 3076 }
160ca0142 Theuns Verwoerd 2017-01-31 3077 if (tb[IFLA_MASTER]) {
33eaf2a6e David Ahern 2017-10-04 3078 err = do_set_master(dev, nla_get_u32(tb[IFLA_MASTER]),
33eaf2a6e David Ahern 2017-10-04 3079 extack);
160ca0142 Theuns Verwoerd 2017-01-31 3080 if (err)
160ca0142 Theuns Verwoerd 2017-01-31 3081 goto out_unregister;
160ca0142 Theuns Verwoerd 2017-01-31 3082 }
3729d5021 Patrick McHardy 2010-02-26 3083 out:
317f4810e Nicolas Dichtel 2015-01-15 3084 if (link_net)
317f4810e Nicolas Dichtel 2015-01-15 3085 put_net(link_net);
81adee47d Eric W. Biederman 2009-11-08 3086 put_net(dest_net);
38f7b870d Patrick McHardy 2007-06-13 3087 return err;
436389007 David S. Miller 2015-03-10 3088 out_unregister:
436389007 David S. Miller 2015-03-10 3089 if (ops->newlink) {
436389007 David S. Miller 2015-03-10 3090 LIST_HEAD(list_kill);
436389007 David S. Miller 2015-03-10 3091
436389007 David S. Miller 2015-03-10 3092 ops->dellink(dev, &list_kill);
436389007 David S. Miller 2015-03-10 3093 unregister_netdevice_many(&list_kill);
436389007 David S. Miller 2015-03-10 3094 } else {
436389007 David S. Miller 2015-03-10 3095 unregister_netdevice(dev);
436389007 David S. Miller 2015-03-10 3096 }
436389007 David S. Miller 2015-03-10 3097 goto out;
38f7b870d Patrick McHardy 2007-06-13 3098 }
38f7b870d Patrick McHardy 2007-06-13 @3099 }
38f7b870d Patrick McHardy 2007-06-13 3100
:::::: The code at line 3099 was first introduced by commit
:::::: 38f7b870d4a6a5d3ec21557e849620cb7d032965 [RTNETLINK]: Link creation API
:::::: TO: Patrick McHardy <kaber@trash.net>
:::::: CC: David S. Miller <davem@sunset.davemloft.net>
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 7394 bytes --]
^ permalink raw reply
* Re: [PATCH net-next] net: phy: consider PHY_IGNORE_INTERRUPT in state machine PHY_NOLINK handling
From: Heiner Kallweit @ 2018-06-01 6:13 UTC (permalink / raw)
To: David Miller; +Cc: f.fainelli, andrew, netdev
In-Reply-To: <20180531.212616.129115220944192049.davem@davemloft.net>
On 01.06.2018 03:26, David Miller wrote:
> From: Heiner Kallweit <hkallweit1@gmail.com>
> Date: Wed, 30 May 2018 22:13:20 +0200
>
>> We can bail out immediately also in case of PHY_IGNORE_INTERRUPT because
>> phy_mac_interupt() informs us once the link is up.
>>
>> Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
>
> When state is PHY_NOLINK, the phy_mac_interrupt() code paths
> will change the state to PHY_CHANGELINK before queueing up
> the state machine invocation.
>
> So I can't even see how we can enter phy_state_machine with
> ->state == PHY_NOLINK is the mac interrupt paths are being
> used properly.
>
We could enter the state machine with PHY_NOLINK in case
any other activity triggers a state machine run whilst
the link is down. But I'm not sure whether such a
scenario exists.
> Therefore it looks like the code as written is harmless.
>
> Did you actually hit a problem with this test or is this
> a change based purely upon code inspection?
>
Right, there is no actual problem, the existing code is
harmless and the change is just based on code inspection.
Small benefit is that it makes clearer that this code path
is applicable in polling mode only.
^ permalink raw reply
* Re: [PATCH net-next] net/smc: fix error return code in smc_setsockopt()
From: Ursula Braun @ 2018-06-01 7:02 UTC (permalink / raw)
To: Wei Yongjun; +Cc: linux-s390, netdev, kernel-janitors
In-Reply-To: <1527733882-149144-1-git-send-email-weiyongjun1@huawei.com>
On 05/31/2018 04:31 AM, Wei Yongjun wrote:
> Fix to return error code -EINVAL instead of 0 if optlen is invalid.
>
> Fixes: 01d2f7e2cdd3 ("net/smc: sockopts TCP_NODELAY and TCP_CORK")
> Signed-off-by: Wei Yongjun <weiyongjun1@huawei.com>
> ---
> net/smc/af_smc.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c
> index 2c369d4..973b447 100644
> --- a/net/smc/af_smc.c
> +++ b/net/smc/af_smc.c
> @@ -1420,7 +1420,7 @@ static int smc_setsockopt(struct socket *sock, int level, int optname,
> return rc;
>
> if (optlen < sizeof(int))
> - return rc;
> + return -EINVAL;
> get_user(val, (int __user *)optval);
>
> lock_sock(sk);
>
Thanks for reporting this error. Your fix is fine, but I think we can get rid of
this check at all, since it is already checked in the tcp-code invoked before with
smc->clcsock->ops->setsockopt(smc->clcsock, level, optname, optval, optlen)
^ permalink raw reply
* Re: [PATCH V4] mlx4_core: allocate ICM memory in page size chunks
From: Michal Hocko @ 2018-06-01 7:31 UTC (permalink / raw)
To: Qing Huang
Cc: Eric Dumazet, David Miller, tariqt, haakon.bugge, yanjun.zhu,
netdev, linux-rdma, linux-kernel, gi-oh.kim,
santosh.shilimkar@oracle.com
In-Reply-To: <7d8f52e1-aa16-d20c-a9a8-35ad88c0b1ab@oracle.com>
On Thu 31-05-18 19:04:46, Qing Huang wrote:
>
>
> On 5/31/2018 2:10 AM, Michal Hocko wrote:
> > On Thu 31-05-18 10:55:32, Michal Hocko wrote:
> > > On Thu 31-05-18 04:35:31, Eric Dumazet wrote:
> > [...]
> > > > I merely copied/pasted from alloc_skb_with_frags() :/
> > > I will have a look at it. Thanks!
> > OK, so this is an example of an incremental development ;).
> >
> > __GFP_NORETRY was added by ed98df3361f0 ("net: use __GFP_NORETRY for
> > high order allocations") to prevent from OOM killer. Yet this was
> > not enough because fb05e7a89f50 ("net: don't wait for order-3 page
> > allocation") didn't want an excessive reclaim for non-costly orders
> > so it made it completely NOWAIT while it preserved __GFP_NORETRY in
> > place which is now redundant. Should I send a patch?
> >
>
> Just curious, how about GFP_ATOMIC flag? Would it work in a similar fashion?
> We experimented
> with it a bit in the past but it seemed to cause other issue in our tests.
> :-)
GFP_ATOMIC is a non-sleeping (aka no reclaim) context with an access to
memory reserves. So the risk is that you deplete those reserves and
cause issues to other subsystems which need them as well.
> By the way, we didn't encounter any OOM killer events. It seemed that the
> mlx4_alloc_icm() triggered slowpath.
> We still had about 2GB free memory while it was highly fragmented.
The compaction was able to make a reasonable forward progress for you.
But considering mlx4_alloc_icm is called with GFP_KERNEL resp. GFP_HIGHUSER
then the OOM killer is clearly possible as long as the order is lower
than 4.
> #0 [ffff8801f308b380] remove_migration_pte at ffffffff811f0e0b
> #1 [ffff8801f308b3e0] rmap_walk_file at ffffffff811cb890
> #2 [ffff8801f308b440] rmap_walk at ffffffff811cbaf2
> #3 [ffff8801f308b450] remove_migration_ptes at ffffffff811f0db0
> #4 [ffff8801f308b490] __unmap_and_move at ffffffff811f2ea6
> #5 [ffff8801f308b4e0] unmap_and_move at ffffffff811f2fc5
> #6 [ffff8801f308b540] migrate_pages at ffffffff811f3219
> #7 [ffff8801f308b5c0] compact_zone at ffffffff811b707e
> #8 [ffff8801f308b650] compact_zone_order at ffffffff811b735d
> #9 [ffff8801f308b6e0] try_to_compact_pages at ffffffff811b7485
> #10 [ffff8801f308b770] __alloc_pages_direct_compact at ffffffff81195f96
> #11 [ffff8801f308b7b0] __alloc_pages_slowpath at ffffffff811978a1
> #12 [ffff8801f308b890] __alloc_pages_nodemask at ffffffff81197ec1
> #13 [ffff8801f308b970] alloc_pages_current at ffffffff811e261f
> #14 [ffff8801f308b9e0] mlx4_alloc_icm at ffffffffa01f39b2 [mlx4_core]
>
> Thanks!
--
Michal Hocko
SUSE Labs
^ permalink raw reply
* Re: [PATCH] netfilter: nft_numgen: fix ptr_ret.cocci warnings
From: Pablo Neira Ayuso @ 2018-06-01 7:46 UTC (permalink / raw)
To: Laura Garcia
Cc: kbuild test robot, kbuild-all, Jozsef Kadlecsik, Florian Westphal,
Netfilter Development Mailing list, coreteam, netdev,
linux-kernel
In-Reply-To: <CAF90-WhsJTVcM+N_7n+4Zf_Knqzxc0UPv4i7bAM6Mvqu-GLHCw@mail.gmail.com>
On Thu, May 24, 2018 at 12:40:04PM +0200, Laura Garcia wrote:
> On Wed, May 23, 2018 at 12:58 PM, kbuild test robot
> <fengguang.wu@intel.com> wrote:
> > From: kbuild test robot <fengguang.wu@intel.com>
> >
> > net/netfilter/nft_numgen.c:117:1-3: WARNING: PTR_ERR_OR_ZERO can be used
> >
> >
> > Use PTR_ERR_OR_ZERO rather than if(IS_ERR(...)) + PTR_ERR
> >
> > Generated by: scripts/coccinelle/api/ptr_ret.cocci
> >
> > Fixes: d734a2888922 ("netfilter: nft_numgen: add map lookups for numgen statements")
> > CC: Laura Garcia Liebana <nevola@gmail.com>
> > Signed-off-by: kbuild test robot <fengguang.wu@intel.com>
>
> Acked-by: Laura Garcia Liebana <nevola@gmail.com>
Applied, thanks.
^ permalink raw reply
* Re: [PATCH v2] netfilter: nfnetlink: Remove VLA usage
From: Pablo Neira Ayuso @ 2018-06-01 7:48 UTC (permalink / raw)
To: Kees Cook
Cc: Jozsef Kadlecsik, Florian Westphal, David S. Miller,
netfilter-devel, coreteam, netdev, linux-kernel
In-Reply-To: <20180530191756.GA39504@beast>
On Wed, May 30, 2018 at 12:17:56PM -0700, Kees Cook wrote:
> In the quest to remove all stack VLA usage from the kernel[1], this
> allocates the maximum size expected for all possible attrs and adds
> sanity-checks at both registration and usage to make sure nothing
> gets out of sync.
>
> [1] https://lkml.kernel.org/r/CA+55aFzCG-zNmZwX4A2FQpadafLfEzK6CC=qPXydAacU1RqZWA@mail.gmail.com
Applied, thanks Kees.
^ permalink raw reply
* Re: [PATCH bpf-next] bpf: prevent non-IPv4 socket to be added into sock hash
From: John Fastabend @ 2018-06-01 7:56 UTC (permalink / raw)
To: Eric Dumazet; +Cc: Wei Wang, netdev, Willem de Bruijn
In-Reply-To: <CANn89iLocj4Gth3R0+a4ppRhYHV=buWSgfEYLg+zJay25D477g@mail.gmail.com>
On 05/31/2018 06:00 PM, Eric Dumazet wrote:
> On Thu, May 31, 2018 at 7:32 PM John Fastabend <john.fastabend@gmail.com> wrote:
>>
>>
>> Hi Wei,
>>
>> Thanks for the report and fix. It would be better to fix the
>> root cause so that IPv6 works as intended.
>>
>> I'm testing the following now,
>>
>> Author: John Fastabend <john.fastabend@gmail.com>
>> Date: Thu May 31 14:38:59 2018 -0700
>>
>> sockmap: fix crash when ipv6 sock is added by adding support for IPv6
>>
>> Apparently we had a testing escape and missed IPv6. This fixes a crash
>> where we assign tcp_prot to IPv6 sockets instead of tcpv6_prot.
>>
>> Signed-off-by: John Fastabend <john.fastabend@gmail.com>
>>
>
> Hi John
>
> In any case, please forward correct attribution for Wei's work, and
> syzbot 'Reported-by'
Will send update with tags in a moment.
>
> Are you sure you are handling IPv4 mapped in IPv6 sockets as well ?
>
No, will look into it. Although I didn't see any code to handle it
in the ./net/tls case either so if there is some issue with this it
could possibly exist in both ULPs. I guess if ipv4 mapped ipv6
changes prot or callbacks then we could stomp on it.
> Thanks.
>
^ permalink raw reply
* Re: [PATCH net-next] netfilter: nf_tables: check msg_type before nft_trans_set(trans)
From: Pablo Neira Ayuso @ 2018-06-01 8:14 UTC (permalink / raw)
To: Florian Westphal
Cc: Alexey Kodanev, netfilter-devel, Jozsef Kadlecsik, coreteam,
netdev
In-Reply-To: <20180531190731.rrwayqgnnnd2fasn@breakpoint.cc>
On Thu, May 31, 2018 at 09:07:31PM +0200, Florian Westphal wrote:
> Alexey Kodanev <alexey.kodanev@oracle.com> wrote:
> > The patch moves the "trans->msg_type == NFT_MSG_NEWSET" check before
> > using nft_trans_set(trans). Otherwise we can get out of bounds read.
>
> Indeed, thanks for fixining this.
>
> Acked-by: Florian Westphal <fw@strlen.de>
Also applied to nf.git, thanks!
^ permalink raw reply
* [PATCH net-next] rtnetlink: Fix null-ptr-deref in rtnl_newlink
From: Prashant Bhole @ 2018-06-01 8:16 UTC (permalink / raw)
To: David S . Miller, Eric Dumazet
Cc: Prashant Bhole, Daniel Borkmann, Alexei Starovoitov, Kirill Tkhai,
Florian Westphal, netdev
In rtnl_newlink(), NULL check is performed on m_ops however member of
ops is accessed. Fixed by accessing member of m_ops instead of ops.
[ 345.432629] BUG: KASAN: null-ptr-deref in rtnl_newlink+0x400/0x1110
[ 345.432629] Read of size 4 at addr 0000000000000088 by task ip/986
[ 345.432629]
[ 345.432629] CPU: 1 PID: 986 Comm: ip Not tainted 4.17.0-rc6+ #9
[ 345.432629] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1ubuntu1 04/01/2014
[ 345.432629] Call Trace:
[ 345.432629] dump_stack+0xc6/0x150
[ 345.432629] ? dump_stack_print_info.cold.0+0x1b/0x1b
[ 345.432629] ? kasan_report+0xb4/0x410
[ 345.432629] kasan_report.cold.4+0x8f/0x91
[ 345.432629] ? rtnl_newlink+0x400/0x1110
[ 345.432629] rtnl_newlink+0x400/0x1110
[...]
Fixes: ccf8dbcd062a ("rtnetlink: Remove VLA usage")
Signed-off-by: Prashant Bhole <bhole_prashant_q7@lab.ntt.co.jp>
---
net/core/rtnetlink.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 8ca49a0e13fb..9a1ba2015ad8 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -2936,7 +2936,7 @@ static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh,
}
if (m_ops) {
- if (ops->slave_maxtype > RTNL_SLAVE_MAX_TYPE)
+ if (m_ops->slave_maxtype > RTNL_SLAVE_MAX_TYPE)
return -EINVAL;
if (m_ops->slave_maxtype &&
--
2.17.0
^ permalink raw reply related
* [PATCH iproute2] devlink: don't enforce NETLINK_{CAP,EXT}_ACK sock opts
From: Ivan Vecera @ 2018-06-01 8:18 UTC (permalink / raw)
To: netdev; +Cc: Arkadi Sharshevsky, Stephen Hemminger
Since commit 049c58539f5d ("devlink: mnlg: Add support for extended ack")
devlink requires NETLINK_{CAP,EXT}_ACK. This prevents devlink from
working with older kernels that don't support these features.
host # ./devlink/devlink
Failed to connect to devlink Netlink
Fixes: 049c58539f5d ("devlink: mnlg: Add support for extended ack")
Cc: Arkadi Sharshevsky <arkadis@mellanox.com>
Cc: Stephen Hemminger <stephen@networkplumber.org>
Signed-off-by: Ivan Vecera <ivecera@redhat.com>
---
devlink/mnlg.c | 14 +++-----------
1 file changed, 3 insertions(+), 11 deletions(-)
diff --git a/devlink/mnlg.c b/devlink/mnlg.c
index 3d28453a..c33c90be 100644
--- a/devlink/mnlg.c
+++ b/devlink/mnlg.c
@@ -271,15 +271,9 @@ struct mnlg_socket *mnlg_socket_open(const char *family_name, uint8_t version)
if (!nlg->nl)
goto err_mnl_socket_open;
- err = mnl_socket_setsockopt(nlg->nl, NETLINK_CAP_ACK, &one,
- sizeof(one));
- if (err)
- goto err_mnl_set_ack;
-
- err = mnl_socket_setsockopt(nlg->nl, NETLINK_EXT_ACK, &one,
- sizeof(one));
- if (err)
- goto err_mnl_set_ext_ack;
+ /* Older kernels may no support capped/extended ACK reporting */
+ mnl_socket_setsockopt(nlg->nl, NETLINK_CAP_ACK, &one, sizeof(one));
+ mnl_socket_setsockopt(nlg->nl, NETLINK_EXT_ACK, &one, sizeof(one));
err = mnl_socket_bind(nlg->nl, 0, MNL_SOCKET_AUTOPID);
if (err < 0)
@@ -305,8 +299,6 @@ struct mnlg_socket *mnlg_socket_open(const char *family_name, uint8_t version)
err_mnlg_socket_recv_run:
err_mnlg_socket_send:
err_mnl_socket_bind:
-err_mnl_set_ext_ack:
-err_mnl_set_ack:
mnl_socket_close(nlg->nl);
err_mnl_socket_open:
free(nlg->buf);
--
2.16.1
^ permalink raw reply related
* [bpf PATCH] bpf: sockmap, fix crash when ipv6 sock is added
From: John Fastabend @ 2018-06-01 8:21 UTC (permalink / raw)
To: edumazet, ast, daniel; +Cc: netdev
This fixes a crash where we assign tcp_prot to IPv6 sockets instead
of tcpv6_prot.
Previously we overwrote the sk->prot field with tcp_prot even in the
AF_INET6 case. This patch ensures the correct tcp_prot and tcpv6_prot
are used.
Fixes: 174a79ff9515 ("bpf: sockmap with sk redirect support")
Reported-by: syzbot+5c063698bdbfac19f363@syzkaller.appspotmail.com
Signed-off-by: John Fastabend <john.fastabend@gmail.com>
Signed-off-by: Wei Wang <weiwan@google.com>
---
kernel/bpf/sockmap.c | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/kernel/bpf/sockmap.c b/kernel/bpf/sockmap.c
index 95a84b2..d16b5a3 100644
--- a/kernel/bpf/sockmap.c
+++ b/kernel/bpf/sockmap.c
@@ -41,6 +41,7 @@
#include <linux/mm.h>
#include <net/strparser.h>
#include <net/tcp.h>
+#include <net/transp_v6.h>
#include <linux/ptr_ring.h>
#include <net/inet_common.h>
#include <linux/sched/signal.h>
@@ -134,6 +135,8 @@ static bool bpf_tcp_stream_read(const struct sock *sk)
}
static struct proto tcp_bpf_proto;
+static struct proto tcpv6_bpf_proto;
+
static int bpf_tcp_init(struct sock *sk)
{
struct smap_psock *psock;
@@ -154,13 +157,21 @@ static int bpf_tcp_init(struct sock *sk)
psock->sk_proto = sk->sk_prot;
if (psock->bpf_tx_msg) {
+ tcpv6_bpf_proto.sendmsg = bpf_tcp_sendmsg;
+ tcpv6_bpf_proto.sendpage = bpf_tcp_sendpage;
+ tcpv6_bpf_proto.recvmsg = bpf_tcp_recvmsg;
+ tcpv6_bpf_proto.stream_memory_read = bpf_tcp_stream_read;
tcp_bpf_proto.sendmsg = bpf_tcp_sendmsg;
tcp_bpf_proto.sendpage = bpf_tcp_sendpage;
tcp_bpf_proto.recvmsg = bpf_tcp_recvmsg;
tcp_bpf_proto.stream_memory_read = bpf_tcp_stream_read;
}
- sk->sk_prot = &tcp_bpf_proto;
+ if (sk->sk_family == AF_INET6)
+ sk->sk_prot = &tcpv6_bpf_proto;
+ else
+ sk->sk_prot = &tcp_bpf_proto;
+
rcu_read_unlock();
return 0;
}
@@ -1072,6 +1083,8 @@ static int bpf_tcp_ulp_register(void)
{
tcp_bpf_proto = tcp_prot;
tcp_bpf_proto.close = bpf_tcp_close;
+ tcpv6_bpf_proto = tcpv6_prot;
+ tcpv6_bpf_proto.close = bpf_tcp_close;
/* Once BPF TX ULP is registered it is never unregistered. It
* will be in the ULP list for the lifetime of the system. Doing
* duplicate registers is not a problem.
^ permalink raw reply related
* Re: [PATCH net-next] rtnetlink: Fix null-ptr-deref in rtnl_newlink
From: Eric Dumazet @ 2018-06-01 8:26 UTC (permalink / raw)
To: bhole_prashant_q7
Cc: David Miller, Daniel Borkmann, Alexei Starovoitov, Kirill Tkhai,
Florian Westphal, netdev, Kees Cook
In-Reply-To: <20180601081658.6968-1-bhole_prashant_q7@lab.ntt.co.jp>
On Fri, Jun 1, 2018 at 4:18 AM Prashant Bhole
<bhole_prashant_q7@lab.ntt.co.jp> wrote:
>
> In rtnl_newlink(), NULL check is performed on m_ops however member of
> ops is accessed. Fixed by accessing member of m_ops instead of ops.
>
> [ 345.432629] BUG: KASAN: null-ptr-deref in rtnl_newlink+0x400/0x1110
> [ 345.432629] Read of size 4 at addr 0000000000000088 by task ip/986
> [ 345.432629]
> [ 345.432629] CPU: 1 PID: 986 Comm: ip Not tainted 4.17.0-rc6+ #9
> [ 345.432629] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1ubuntu1 04/01/2014
> [ 345.432629] Call Trace:
> [ 345.432629] dump_stack+0xc6/0x150
> [ 345.432629] ? dump_stack_print_info.cold.0+0x1b/0x1b
> [ 345.432629] ? kasan_report+0xb4/0x410
> [ 345.432629] kasan_report.cold.4+0x8f/0x91
> [ 345.432629] ? rtnl_newlink+0x400/0x1110
> [ 345.432629] rtnl_newlink+0x400/0x1110
> [...]
>
> Fixes: ccf8dbcd062a ("rtnetlink: Remove VLA usage")
> Signed-off-by: Prashant Bhole <bhole_prashant_q7@lab.ntt.co.jp>
> ---
> net/core/rtnetlink.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
> index 8ca49a0e13fb..9a1ba2015ad8 100644
> --- a/net/core/rtnetlink.c
> +++ b/net/core/rtnetlink.c
> @@ -2936,7 +2936,7 @@ static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh,
> }
>
> if (m_ops) {
> - if (ops->slave_maxtype > RTNL_SLAVE_MAX_TYPE)
> + if (m_ops->slave_maxtype > RTNL_SLAVE_MAX_TYPE)
> return -EINVAL;
Oh nice
CC Kees Cook.
^ permalink raw reply
* Re: [PATCH bpf 1/2] bpf: fix alignment of netns_dev/netns_ino fields in bpf_{map,prog}_info
From: Alexei Starovoitov @ 2018-06-01 8:41 UTC (permalink / raw)
To: Linus Torvalds, Eugene Syromiatnikov, netdev, linux-kernel,
Martin KaFai Lau, Daniel Borkmann, Alexei Starovoitov,
David S. Miller, Jiri Olsa, Ingo Molnar, Lawrence Brakmo,
Andrey Ignatov, Jakub Kicinski, John Fastabend
In-Reply-To: <20180601031210.GA30533@altlinux.org>
On Fri, Jun 01, 2018 at 06:12:10AM +0300, Dmitry V. Levin wrote:
> Hi,
>
> Looks like the ABI bug in bpf_map_info and bpf_prog info introduced
> in 4.16 is going to slip into 4.17, causing extra pain to 32-bit
> userspace. I'm adding Linus to this thread in hope it might help
> to get a fix applied before 4.17 is released.
The issue identified in patch 1 is valid.
These two fields won't be properly accessible by 32-bit user space
on 64-bit kernel.
But the fix in patch 1 is wrong.
The patch 2 is completely unnecessary.
Everyone can also see that the patches are still marked as 'new' in patchworks
meaning that we didn't process them.
At the moment many networking folks are traveling to netconf
and we only had a chance to discuss this set last night.
We'll try to send a fix in coming days.
But regardless whether 4.17 is realesed this sunday or not
we're not going to rush wrong patch in without proper code review
and discussion.
That future patch either will land in 4.17 (if it's dealyed into next sunday)
or it will be sent to stable.
To speed up the situation next time please report the issue that you find
to public netdev mailing list instead of using proprietary distro emails.
Thanks.
> On Wed, May 30, 2018 at 09:18:58PM +0300, Dmitry V. Levin wrote:
> > On Sun, May 27, 2018 at 01:28:42PM +0200, Eugene Syromiatnikov wrote:
> > > Recent introduction of netns_dev/netns_ino to bpf_map_info/bpf_prog info
> > > has broken compat, as offsets of these fields are different in 32-bit
> > > and 64-bit ABIs. One fix (other than implementing compat support in
> > > syscall in order to handle this discrepancy) is to use __aligned_u64
> > > instead of __u64 for these fields.
> > >
> > > Reported-by: Dmitry V. Levin <ldv@altlinux.org>
> > > Fixes: 52775b33bb507 ("bpf: offload: report device information about
> > > offloaded maps")
> > > Fixes: 675fc275a3a2d ("bpf: offload: report device information for
> > > offloaded programs")
> > >
> > > Signed-off-by: Eugene Syromiatnikov <esyr@redhat.com>
> >
> > Reviewed-by: "Dmitry V. Levin" <ldv@altlinux.org>
> > Cc: <stable@vger.kernel.org> # v4.16+
> >
> > Thanks,
> >
> > > ---
> > > include/uapi/linux/bpf.h | 8 ++++----
> > > tools/include/uapi/linux/bpf.h | 8 ++++----
> > > 2 files changed, 8 insertions(+), 8 deletions(-)
> > >
> > > diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
> > > index c5ec897..903010a 100644
> > > --- a/include/uapi/linux/bpf.h
> > > +++ b/include/uapi/linux/bpf.h
> > > @@ -1017,8 +1017,8 @@ struct bpf_prog_info {
> > > __aligned_u64 map_ids;
> > > char name[BPF_OBJ_NAME_LEN];
> > > __u32 ifindex;
> > > - __u64 netns_dev;
> > > - __u64 netns_ino;
> > > + __aligned_u64 netns_dev;
> > > + __aligned_u64 netns_ino;
> > > } __attribute__((aligned(8)));
> > >
> > > struct bpf_map_info {
> > > @@ -1030,8 +1030,8 @@ struct bpf_map_info {
> > > __u32 map_flags;
> > > char name[BPF_OBJ_NAME_LEN];
> > > __u32 ifindex;
> > > - __u64 netns_dev;
> > > - __u64 netns_ino;
> > > + __aligned_u64 netns_dev;
> > > + __aligned_u64 netns_ino;
> > > } __attribute__((aligned(8)));
> > >
> > > /* User bpf_sock_addr struct to access socket fields and sockaddr struct passed
> > > diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
> > > index c5ec897..903010a 100644
> > > --- a/tools/include/uapi/linux/bpf.h
> > > +++ b/tools/include/uapi/linux/bpf.h
> > > @@ -1017,8 +1017,8 @@ struct bpf_prog_info {
> > > __aligned_u64 map_ids;
> > > char name[BPF_OBJ_NAME_LEN];
> > > __u32 ifindex;
> > > - __u64 netns_dev;
> > > - __u64 netns_ino;
> > > + __aligned_u64 netns_dev;
> > > + __aligned_u64 netns_ino;
> > > } __attribute__((aligned(8)));
> > >
> > > struct bpf_map_info {
> > > @@ -1030,8 +1030,8 @@ struct bpf_map_info {
> > > __u32 map_flags;
> > > char name[BPF_OBJ_NAME_LEN];
> > > __u32 ifindex;
> > > - __u64 netns_dev;
> > > - __u64 netns_ino;
> > > + __aligned_u64 netns_dev;
> > > + __aligned_u64 netns_ino;
> > > } __attribute__((aligned(8)));
> > >
> > > /* User bpf_sock_addr struct to access socket fields and sockaddr struct passed
>
>
> --
> ldv
^ permalink raw reply
* Re: linux-next: build failure after merge of the net-next tree
From: Alexei Starovoitov @ 2018-06-01 8:52 UTC (permalink / raw)
To: Stephen Rothwell
Cc: David Miller, Networking, Linux-Next Mailing List,
Linux Kernel Mailing List, Jakub Kicinski, Alexei Starovoitov,
Daniel Borkmann
In-Reply-To: <20180601135943.66b90890@canb.auug.org.au>
On Fri, Jun 01, 2018 at 01:59:43PM +1000, Stephen Rothwell wrote:
> Hi all,
>
> On Thu, 31 May 2018 07:38:55 +1000 Stephen Rothwell <sfr@canb.auug.org.au> wrote:
> >
> > On Tue, 29 May 2018 13:25:48 +1000 Stephen Rothwell <sfr@canb.auug.org.au> wrote:
> > >
> > > After merging the net-next tree, today's linux-next build (x86_64
> > > allmodconfig) failed like this:
> > >
> > > x86_64-linux-ld: unknown architecture of input file `net/bpfilter/bpfilter_umh.o' is incompatible with i386:x86-64 output
> > >
> > > Caused by commit
> > >
> > > d2ba09c17a06 ("net: add skeleton of bpfilter kernel module")
> > >
> > > In my builds, the host is PowerPC 64 LE ...
> > >
> > > I have reverted that commit along with
> > >
> > > 61a552eb487f ("bpfilter: fix build dependency")
> > > 13405468f49d ("bpfilter: don't pass O_CREAT when opening console for debug")
> > >
> > > for today.
> >
> > I am still getting this failure (well, at least yesterday I did).
>
> Still happened today. My guess is that bpfilter_umh needs to be built
> with the kernel compiler (not the host compiler - since ir is meant to
> run on the some machine as the kernel, right?) but will require the
> kernel architecture libc etc
>
>
> I replaced the reverts above with the following:
>
> From: Stephen Rothwell <sfr@canb.auug.org.au>
> Date: Fri, 1 Jun 2018 13:33:28 +1000
> Subject: [PATCH] net: bpfilter: mark as BROKEN for now
>
> This does not build in a cross compile environment
>
> Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
> ---
> net/bpfilter/Kconfig | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/net/bpfilter/Kconfig b/net/bpfilter/Kconfig
> index a948b072c28f..ea4be72fdf6e 100644
> --- a/net/bpfilter/Kconfig
> +++ b/net/bpfilter/Kconfig
> @@ -2,6 +2,7 @@ menuconfig BPFILTER
> bool "BPF based packet filtering framework (BPFILTER)"
> default n
> depends on NET && BPF && INET
> + depends on BROKEN
yeah. that's another option.
Sorry for delay. networking folks are traveling to netconf.
The issue is being discussed here:
https://patchwork.ozlabs.org/patch/921597/
Currently we're thinking how to add a check that hostcc's arch
is equal to cross-cc target arch and ideally equal to arch
of the host where it will be run.
^ permalink raw reply
* Re: [PATCH] net: core: improve the tx_hash calculating
From: Sergei Shtylyov @ 2018-06-01 8:58 UTC (permalink / raw)
To: Tonghao Zhang, netdev
In-Reply-To: <1527761641-22034-1-git-send-email-xiangxia.m.yue@gmail.com>
Hello!
On 5/31/2018 1:14 PM, Tonghao Zhang wrote:
> Use the % instead of while, and it may simple code and improve
> the calculating. The real_num_tx_queues has been checked when
> allocating and setting it.
>
> Signed-off-by: Tonghao Zhang <xiangxia.m.yue@gmail.com>
> ---
> net/core/dev.c | 8 +++-----
> 1 file changed, 3 insertions(+), 5 deletions(-)
>
> diff --git a/net/core/dev.c b/net/core/dev.c
> index 1844d9b..edc5b75 100644
> --- a/net/core/dev.c
> +++ b/net/core/dev.c
> @@ -2617,15 +2617,13 @@ void netif_device_attach(struct net_device *dev)
> */
> static u16 skb_tx_hash(const struct net_device *dev, struct sk_buff *skb)
> {
> - u32 hash;
> u16 qoffset = 0;
> u16 qcount = dev->real_num_tx_queues;
>
> if (skb_rx_queue_recorded(skb)) {
> - hash = skb_get_rx_queue(skb);
> - while (unlikely(hash >= qcount))
> - hash -= qcount;
> - return hash;
> + /* When setting the real_num_tx_queues, we make sure
> + * real_num_tx_queues != 0. */
In the networking code, multiline comments should look like:
/* bla
* bla
*/
> + return skb_get_rx_queue(skb) % qcount;
> }
>
> if (dev->num_tc) {
MBR, Sergei
^ permalink raw reply
* Re: [PATCH 15/19] net: qualcomm: MODULE_DEVICE_TABLE(serdev)
From: Stefan Wahren @ 2018-06-01 8:59 UTC (permalink / raw)
To: Ricardo Ribalda Delgado, linux-kernel, linux-serial
Cc: Lino Sanfilippo, David S . Miller, Rob Herring, Johan Hovold,
netdev
In-Reply-To: <20180529131014.18641-16-ricardo.ribalda@gmail.com>
Hi Ricardo,
Am 29.05.2018 um 15:10 schrieb Ricardo Ribalda Delgado:
> Export serdev table to the module header, allowing module autoload via
> udev/modprobe.
>
> Cc: Lino Sanfilippo <LinoSanfilippo@gmx.de>
> Cc: David S. Miller <davem@davemloft.net>
> Cc: Stefan Wahren <stefan.wahren@i2se.com>
> Cc: Rob Herring <robh@kernel.org>
> Cc: Johan Hovold <johan@kernel.org>
> Cc: netdev@vger.kernel.org
> Signed-off-by: Ricardo Ribalda Delgado <ricardo.ribalda@gmail.com>
> ---
> drivers/net/ethernet/qualcomm/qca_uart.c | 7 +++++++
> 1 file changed, 7 insertions(+)
>
> diff --git a/drivers/net/ethernet/qualcomm/qca_uart.c b/drivers/net/ethernet/qualcomm/qca_uart.c
> index db6068cd7a1f..bb7aed805083 100644
> --- a/drivers/net/ethernet/qualcomm/qca_uart.c
> +++ b/drivers/net/ethernet/qualcomm/qca_uart.c
> @@ -405,6 +405,12 @@ static void qca_uart_remove(struct serdev_device *serdev)
> free_netdev(qca->net_dev);
> }
>
> +static struct serdev_device_id qca_uart_serdev_id[] = {
> + { QCAUART_DRV_NAME, },
i guess the id must be stable, so in case someone changes the driver
name this has unexpected side effects?
Apart from that i'm fine with this patch.
Thanks
Stefan
> + {},
> +};
> +MODULE_DEVICE_TABLE(serdev, qca_uart_serdev_id);
> +
> static struct serdev_device_driver qca_uart_driver = {
> .probe = qca_uart_probe,
> .remove = qca_uart_remove,
> @@ -412,6 +418,7 @@ static struct serdev_device_driver qca_uart_driver = {
> .name = QCAUART_DRV_NAME,
> .of_match_table = of_match_ptr(qca_uart_of_match),
> },
> + .id_table = qca_uart_serdev_id,
> };
>
> module_serdev_device_driver(qca_uart_driver);
^ permalink raw reply
* Re: [PATCH net-next 1/5] net: aquantia: Ethtool based ring size configuration
From: Igor Russkikh @ 2018-06-01 9:19 UTC (permalink / raw)
To: Jakub Kicinski
Cc: David S . Miller, netdev, David Arcari, Pavel Belous,
Anton Mikaev
In-Reply-To: <20180529120403.3f89a394@cakuba>
>> +
>> + spin_lock(&aq_nic->aq_spinlock);
>> +
>> + if (netif_running(ndev))
>> + dev_close(ndev);
>
> I don't think you can hold a spinlock around dev_close()/dev_open()
> calls.
Thanks Jakub, think you are right, will consider changing this lock to mutex.
>> + if (!netif_running(ndev))
>> + err = dev_open(ndev);
>
> Will this not open the device regardless if it was open before or not?
Correct, thanks!
BR, Igor
^ permalink raw reply
* [RFC PATCH 00/16] bpf, bounded loop support work in progress
From: John Fastabend @ 2018-06-01 9:32 UTC (permalink / raw)
To: alexei.starovoitov, daniel, davem; +Cc: netdev
This series is an early preview of ongoing work to support loops
inside BPF verifier. The code is rough in spots (more rough the
further you get into the series) but we have some signs of life!
The following code runs and is verified,
SEC("classifier_tc_loop1")
int _tc_loop(struct __sk_buff *ctx)
{
void *data = (void *)(unsigned long)ctx->data;
void *data_end = (void *)(unsigned long)ctx->data_end;
__u8 i = 0, j = 0, k = 0, *p;
if (data + 2 > data_end)
return TC_ACT_OK;
p = data;
j = p[0];
if (data + 101 > data_end)
return TC_ACT_OK;
if (j < 100)
return TC_ACT_OK;
#pragma nounroll
while (i < j) {
k += p[i];
i++;
}
ctx->mark = k;
return TC_ACT_OK;
}
perhaps even more important many invalid loops are caught and
rejected. There are still a few cases that need to be handled
but largely things are working. And lots of code cleanup,
polishing and improvements sill needed but worth sharing
I think. Even if no one reads the code line by line the commit
messages have the description.
The series is broken into three parts.
Part1: Build the basic infrastruce. Basic Blocks, CFG and DOM are
built. (work done by Jiong).
Part2: Verify loops are bounded and encourage the state pruning
logic to prune as many states as possible.
Part3: Tests. Largely tbd at this point although I've been
doing lots of manual poking around with good/bad/ugly C programs.
Some high level details around design decisions for each part but
please see patch descriptions for more.
First Part1 Jiong chose to use Tarjan algorithm to build DOM.
(We also have an iterative solution if that is prefered but in
theory at least Tarjan has better running time.) Also we have
calculated the pdom as well but it is currently unused.
For all Part2 gory details please see patch,
"bpf: verifier, add initial support to allow bounded loops"
The high level design is as follows,
i. Use DOM to find loops
ii. Find induction variables in loop
iii. Verify termination by comparing induction variable (inc/dec)
against the JMP op. Propagate min/max values into insn aux
data.
iv. At do_check time ensure induction variable is bounded as
required to ensure loop termination. These are a form of
restriction on valid values for the registers.
v. Encourage state pruning by using known bounds from
previous induction step. e.g. if a scalar increments from
0 to 100 we know min/max values that are vali for every
iteration.
vi. Loop state is usually pruned early but if not we can simply
run the loop costing verifier complexity.
There is still lots of work to finish up all the pieces but we wanted
to share the current design.
Thanks,
John
---
Jiong Wang (11):
bpf: cfg: partition basic blocks for each subprog
bpf: cfg: add edges between basic blocks to form CFG
bpf: cfg: build domination tree using Tarjan algorithm
bpf: cfg: detect loop use domination information
bpf: cfg: detect unreachable basic blocks
bpf: cfg: move find_subprog/add_subprog to cfg.c
bpf: cfg: build call graph and detect unreachable/recursive call
bpf: cfg: remove push_insn and check_cfg
bpf: cfg: reduce k*alloc/free call by using memory pool for allocating nodes
bpf: cfg: reduce memory usage by using singly list + compat pointer
bpf: cfg: detect irreducible loop using Eric Stoltz algorithm
John Fastabend (5):
bpf: cfg: pretty print CFG and DOM
bpf: verifier, can ptr range be calculated with scalar ALU op
bpf: verifier, add initial support to allow bounded loops
bpf: verifier, simple loop examples
bpf: tools: dbg patch to turn on debugging and add primitive examples
include/linux/bpf_verifier.h | 28
kernel/bpf/Makefile | 2
kernel/bpf/cfg.c | 2060 ++++++++++++++++++++++++
kernel/bpf/cfg.h | 56 +
kernel/bpf/verifier.c | 499 +++---
samples/bpf/xdp2skb_meta_kern.c | 57 +
tools/lib/bpf/bpf.c | 2
tools/lib/bpf/libbpf.c | 7
tools/testing/selftests/bpf/Makefile | 5
tools/testing/selftests/bpf/test_bad_loop1.c | 47 +
tools/testing/selftests/bpf/test_bad_loop2.c | 45 +
tools/testing/selftests/bpf/test_bad_loop3.c | 47 +
tools/testing/selftests/bpf/test_basic_loop1.c | 44 +
tools/testing/selftests/bpf/test_basic_loop2.c | 48 +
tools/testing/selftests/bpf/test_basic_loop3.c | 51 +
15 files changed, 2711 insertions(+), 287 deletions(-)
create mode 100644 kernel/bpf/cfg.c
create mode 100644 kernel/bpf/cfg.h
create mode 100644 tools/testing/selftests/bpf/test_bad_loop1.c
create mode 100644 tools/testing/selftests/bpf/test_bad_loop2.c
create mode 100644 tools/testing/selftests/bpf/test_bad_loop3.c
create mode 100644 tools/testing/selftests/bpf/test_basic_loop1.c
create mode 100644 tools/testing/selftests/bpf/test_basic_loop2.c
create mode 100644 tools/testing/selftests/bpf/test_basic_loop3.c
^ permalink raw reply
* [RFC PATCH 01/16] bpf: cfg: partition basic blocks for each subprog
From: John Fastabend @ 2018-06-01 9:32 UTC (permalink / raw)
To: alexei.starovoitov, daniel, davem; +Cc: netdev
In-Reply-To: <20180601092646.15353.28269.stgit@john-Precision-Tower-5810>
From: Jiong Wang <jiong.wang@netronome.com>
"check_subprogs" has partitioned subprogs and is doing insn scan for each
subprog already, this patch extends it to also partition basic blocks (BB)
for each subprog.
- The first insn for each subprog start a BB.
- Branch (both cond and absolute) target start a BB.
- Insn immediately follows branch insn start a BB.
Insn immediately follows exit and within subprog start a BB.
BBs for each subprog are organized as a list in ascending head.
Two special BBs, entry and exit are added as well.
Signed-off-by: Jiong Wang <jiong.wang@netronome.com>
Signed-off-by: John Fastabend <john.fastabend@gmail.com>
---
include/linux/bpf_verifier.h | 1
kernel/bpf/Makefile | 2 -
kernel/bpf/cfg.c | 93 ++++++++++++++++++++++++++++++++++++++++++
kernel/bpf/cfg.h | 16 +++++++
kernel/bpf/verifier.c | 57 +++++++++++++++++++++++---
5 files changed, 162 insertions(+), 7 deletions(-)
create mode 100644 kernel/bpf/cfg.c
create mode 100644 kernel/bpf/cfg.h
diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h
index 38b04f5..c70faf5 100644
--- a/include/linux/bpf_verifier.h
+++ b/include/linux/bpf_verifier.h
@@ -177,6 +177,7 @@ static inline bool bpf_verifier_log_needed(const struct bpf_verifier_log *log)
struct bpf_subprog_info {
u32 start; /* insn idx of function entry point */
u16 stack_depth; /* max. stack depth used by this function */
+ struct list_head bbs; /* basic blocks list. */
};
/* single container for all structs
diff --git a/kernel/bpf/Makefile b/kernel/bpf/Makefile
index f27f549..3ee9036 100644
--- a/kernel/bpf/Makefile
+++ b/kernel/bpf/Makefile
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
obj-y := core.o
-obj-$(CONFIG_BPF_SYSCALL) += syscall.o verifier.o inode.o helpers.o tnum.o
+obj-$(CONFIG_BPF_SYSCALL) += syscall.o verifier.o inode.o helpers.o tnum.o cfg.o
obj-$(CONFIG_BPF_SYSCALL) += hashtab.o arraymap.o percpu_freelist.o bpf_lru_list.o lpm_trie.o map_in_map.o
obj-$(CONFIG_BPF_SYSCALL) += disasm.o
obj-$(CONFIG_BPF_SYSCALL) += btf.o
diff --git a/kernel/bpf/cfg.c b/kernel/bpf/cfg.c
new file mode 100644
index 0000000..b1af714
--- /dev/null
+++ b/kernel/bpf/cfg.c
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (C) 2018 Netronome Systems, Inc. */
+/* This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ */
+
+#include <linux/bpf_verifier.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+
+#include "cfg.h"
+
+struct bb_node {
+ struct list_head l;
+ u16 head;
+};
+
+#define bb_prev(bb) list_prev_entry(bb, l)
+#define bb_next(bb) list_next_entry(bb, l)
+#define bb_first(bb_list) list_first_entry(bb_list, struct bb_node, l)
+#define bb_last(bb_list) list_last_entry(bb_list, struct bb_node, l)
+#define entry_bb(bb_list) bb_first(bb_list)
+#define exit_bb(bb_list) bb_last(bb_list)
+
+int subprog_append_bb(struct list_head *bb_list, int head)
+{
+ struct bb_node *new_bb, *bb;
+
+ list_for_each_entry(bb, bb_list, l) {
+ if (bb->head == head)
+ return 0;
+ else if (bb->head > head)
+ break;
+ }
+
+ bb = bb_prev(bb);
+ new_bb = kzalloc(sizeof(*new_bb), GFP_KERNEL);
+ if (!new_bb)
+ return -ENOMEM;
+
+ new_bb->head = head;
+ list_add(&new_bb->l, &bb->l);
+
+ return 0;
+}
+
+int subprog_fini_bb(struct list_head *bb_list, int subprog_end)
+{
+ struct bb_node *bb = kzalloc(sizeof(*bb), GFP_KERNEL);
+
+ if (!bb)
+ return -ENOMEM;
+ /* entry bb. */
+ bb->head = -1;
+ list_add(&bb->l, bb_list);
+
+ bb = kzalloc(sizeof(*bb), GFP_KERNEL);
+ if (!bb)
+ return -ENOMEM;
+ /* exit bb. */
+ bb->head = subprog_end;
+ list_add_tail(&bb->l, bb_list);
+
+ return 0;
+}
+
+int subprog_init_bb(struct list_head *bb_list, int subprog_start)
+{
+ int ret;
+
+ INIT_LIST_HEAD(bb_list);
+ ret = subprog_append_bb(bb_list, subprog_start);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+void subprog_free_bb(struct bpf_subprog_info *subprog, int end_idx)
+{
+ int i = 0;
+
+ for (; i <= end_idx; i++) {
+ struct list_head *bbs = &subprog[i].bbs;
+ struct bb_node *bb, *tmp;
+
+ list_for_each_entry_safe(bb, tmp, bbs, l) {
+ list_del(&bb->l);
+ kfree(bb);
+ }
+ }
+}
diff --git a/kernel/bpf/cfg.h b/kernel/bpf/cfg.h
new file mode 100644
index 0000000..4092145
--- /dev/null
+++ b/kernel/bpf/cfg.h
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (C) 2018 Netronome Systems, Inc. */
+/* This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ */
+
+#ifndef __BPF_CFG_H__
+#define __BPF_CFG_H__
+
+int subprog_append_bb(struct list_head *bb_list, int head);
+int subprog_fini_bb(struct list_head *bb_list, int subprog_end);
+int subprog_init_bb(struct list_head *bb_list, int subprog_start);
+void subprog_free_bb(struct bpf_subprog_info *subprog, int end_idx);
+
+#endif
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 1fd9667b..523e440 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -24,6 +24,7 @@
#include <linux/sort.h>
#include <linux/perf_event.h>
+#include "cfg.h"
#include "disasm.h"
static const struct bpf_verifier_ops * const bpf_verifier_ops[] = {
@@ -807,6 +808,7 @@ static int check_subprogs(struct bpf_verifier_env *env)
struct bpf_subprog_info *subprog = env->subprog_info;
struct bpf_insn *insn = env->prog->insnsi;
int insn_cnt = env->prog->len;
+ struct list_head *cur_bb_list;
/* Add entry function. */
ret = add_subprog(env, 0);
@@ -841,20 +843,46 @@ static int check_subprogs(struct bpf_verifier_env *env)
for (i = 0; i < env->subprog_cnt; i++)
verbose(env, "func#%d @%d\n", i, subprog[i].start);
- /* now check that all jumps are within the same subprog */
subprog_start = subprog[cur_subprog].start;
subprog_end = subprog[cur_subprog + 1].start;
+ cur_bb_list = &subprog[cur_subprog].bbs;
+ ret = subprog_init_bb(cur_bb_list, subprog_start);
+ if (ret < 0)
+ goto free_nodes;
+ /* now check that all jumps are within the same subprog */
for (i = 0; i < insn_cnt; i++) {
u8 code = insn[i].code;
if (BPF_CLASS(code) != BPF_JMP)
goto next;
- if (BPF_OP(code) == BPF_EXIT || BPF_OP(code) == BPF_CALL)
+
+ if (BPF_OP(code) == BPF_EXIT) {
+ if (i + 1 < subprog_end) {
+ ret = subprog_append_bb(cur_bb_list, i + 1);
+ if (ret < 0)
+ goto free_nodes;
+ }
+ goto next;
+ }
+
+ if (BPF_OP(code) == BPF_CALL)
goto next;
+
off = i + insn[i].off + 1;
if (off < subprog_start || off >= subprog_end) {
verbose(env, "jump out of range from insn %d to %d\n", i, off);
- return -EINVAL;
+ ret = -EINVAL;
+ goto free_nodes;
+ }
+
+ ret = subprog_append_bb(cur_bb_list, off);
+ if (ret < 0)
+ goto free_nodes;
+
+ if (i + 1 < subprog_end) {
+ ret = subprog_append_bb(cur_bb_list, i + 1);
+ if (ret < 0)
+ goto free_nodes;
}
next:
if (i == subprog_end - 1) {
@@ -865,15 +893,32 @@ static int check_subprogs(struct bpf_verifier_env *env)
if (code != (BPF_JMP | BPF_EXIT) &&
code != (BPF_JMP | BPF_JA)) {
verbose(env, "last insn is not an exit or jmp\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto free_nodes;
}
+
+ ret = subprog_fini_bb(cur_bb_list, subprog_end);
+ if (ret < 0)
+ goto free_nodes;
subprog_start = subprog_end;
cur_subprog++;
- if (cur_subprog < env->subprog_cnt)
+ if (cur_subprog < env->subprog_cnt) {
subprog_end = subprog[cur_subprog + 1].start;
+ cur_bb_list = &subprog[cur_subprog].bbs;
+ ret = subprog_init_bb(cur_bb_list,
+ subprog_start);
+ if (ret < 0)
+ goto free_nodes;
+ }
}
}
- return 0;
+
+ ret = 0;
+
+free_nodes:
+ subprog_free_bb(subprog, cur_subprog == env->subprog_cnt ?
+ cur_subprog - 1 : cur_subprog);
+ return ret;
}
static
^ permalink raw reply related
* [RFC PATCH 02/16] bpf: cfg: add edges between basic blocks to form CFG
From: John Fastabend @ 2018-06-01 9:32 UTC (permalink / raw)
To: alexei.starovoitov, daniel, davem; +Cc: netdev
In-Reply-To: <20180601092646.15353.28269.stgit@john-Precision-Tower-5810>
From: Jiong Wang <jiong.wang@netronome.com>
This patch add edges between basic blocks. Both edges for predecessors and
successors are added.
Signed-off-by: Jiong Wang <jiong.wang@netronome.com>
Signed-off-by: John Fastabend <john.fastabend@gmail.com>
---
kernel/bpf/cfg.c | 129 ++++++++++++++++++++++++++++++++++++++++++++++++-
kernel/bpf/cfg.h | 1
kernel/bpf/verifier.c | 3 +
3 files changed, 131 insertions(+), 2 deletions(-)
diff --git a/kernel/bpf/cfg.c b/kernel/bpf/cfg.c
index b1af714..208aac7 100644
--- a/kernel/bpf/cfg.c
+++ b/kernel/bpf/cfg.c
@@ -11,8 +11,16 @@
#include "cfg.h"
+struct edge_node {
+ struct list_head l;
+ struct bb_node *src;
+ struct bb_node *dst;
+};
+
struct bb_node {
struct list_head l;
+ struct list_head e_prevs;
+ struct list_head e_succs;
u16 head;
};
@@ -39,6 +47,8 @@ int subprog_append_bb(struct list_head *bb_list, int head)
if (!new_bb)
return -ENOMEM;
+ INIT_LIST_HEAD(&new_bb->e_prevs);
+ INIT_LIST_HEAD(&new_bb->e_succs);
new_bb->head = head;
list_add(&new_bb->l, &bb->l);
@@ -53,6 +63,8 @@ int subprog_fini_bb(struct list_head *bb_list, int subprog_end)
return -ENOMEM;
/* entry bb. */
bb->head = -1;
+ INIT_LIST_HEAD(&bb->e_prevs);
+ INIT_LIST_HEAD(&bb->e_succs);
list_add(&bb->l, bb_list);
bb = kzalloc(sizeof(*bb), GFP_KERNEL);
@@ -60,6 +72,8 @@ int subprog_fini_bb(struct list_head *bb_list, int subprog_end)
return -ENOMEM;
/* exit bb. */
bb->head = subprog_end;
+ INIT_LIST_HEAD(&bb->e_prevs);
+ INIT_LIST_HEAD(&bb->e_succs);
list_add_tail(&bb->l, bb_list);
return 0;
@@ -77,15 +91,126 @@ int subprog_init_bb(struct list_head *bb_list, int subprog_start)
return 0;
}
+static struct bb_node *search_bb_with_head(struct list_head *bb_list, int head)
+{
+ struct bb_node *bb;
+
+ list_for_each_entry(bb, bb_list, l) {
+ if (bb->head == head)
+ return bb;
+ }
+
+ return NULL;
+}
+
+int subprog_add_bb_edges(struct bpf_insn *insns, struct list_head *bb_list)
+{
+ struct bb_node *bb, *exit_bb;
+ struct edge_node *edge;
+
+ bb = entry_bb(bb_list);
+ edge = kcalloc(2, sizeof(*edge), GFP_KERNEL);
+ if (!edge)
+ return -ENOMEM;
+ edge->src = bb;
+ edge->dst = bb_next(bb);
+ list_add_tail(&edge->l, &bb->e_succs);
+ edge[1].src = edge->src;
+ edge[1].dst = edge->dst;
+ list_add_tail(&edge[1].l, &edge[1].dst->e_prevs);
+
+ exit_bb = exit_bb(bb_list);
+ bb = bb_next(bb);
+ list_for_each_entry_from(bb, &exit_bb->l, l) {
+ bool has_fallthrough, only_has_fallthrough;
+ bool has_branch, only_has_branch;
+ struct bb_node *next_bb = bb_next(bb);
+ int tail = next_bb->head - 1;
+ struct bpf_insn insn;
+ u8 code;
+
+ edge = kcalloc(2, sizeof(*edge), GFP_KERNEL);
+ if (!edge)
+ return -ENOMEM;
+ edge->src = bb;
+ edge[1].src = bb;
+
+ insn = insns[tail];
+ code = insn.code;
+ only_has_fallthrough = BPF_CLASS(code) != BPF_JMP ||
+ BPF_OP(code) == BPF_EXIT;
+ has_fallthrough = only_has_fallthrough ||
+ (BPF_CLASS(code) == BPF_JMP &&
+ BPF_OP(code) != BPF_CALL &&
+ BPF_OP(code) != BPF_JA);
+ only_has_branch = BPF_CLASS(code) == BPF_JMP &&
+ BPF_OP(code) == BPF_JA;
+ has_branch = only_has_branch ||
+ (BPF_CLASS(code) == BPF_JMP &&
+ BPF_OP(code) != BPF_EXIT &&
+ BPF_OP(code) != BPF_CALL);
+
+ if (has_fallthrough) {
+ if (BPF_CLASS(code) == BPF_JMP &&
+ BPF_OP(code) == BPF_EXIT)
+ next_bb = exit_bb;
+ edge->dst = next_bb;
+ edge[1].dst = next_bb;
+ list_add_tail(&edge->l, &bb->e_succs);
+ list_add_tail(&edge[1].l, &edge[1].dst->e_prevs);
+ edge = NULL;
+ }
+
+ if (has_branch) {
+ struct bb_node *tgt;
+
+ if (!edge) {
+ edge = kcalloc(2, sizeof(*edge), GFP_KERNEL);
+ if (!edge)
+ return -ENOMEM;
+ edge->src = bb;
+ edge[1].src = bb;
+ }
+
+ tgt = search_bb_with_head(bb_list,
+ tail + insn.off + 1);
+ if (!tgt)
+ return -EINVAL;
+
+ edge->dst = tgt;
+ edge[1].dst = tgt;
+ list_add_tail(&edge->l, &bb->e_succs);
+ list_add_tail(&edge[1].l, &tgt->e_prevs);
+ }
+ }
+
+ return 0;
+}
+
+static void subprog_free_edge(struct bb_node *bb)
+{
+ struct list_head *succs = &bb->e_succs;
+ struct edge_node *e, *tmp;
+
+ /* prevs and succs are allocated as pair, succs is the start addr. */
+ list_for_each_entry_safe(e, tmp, succs, l) {
+ list_del(&e->l);
+ kfree(e);
+ }
+}
+
void subprog_free_bb(struct bpf_subprog_info *subprog, int end_idx)
{
int i = 0;
for (; i <= end_idx; i++) {
struct list_head *bbs = &subprog[i].bbs;
- struct bb_node *bb, *tmp;
+ struct bb_node *bb, *tmp, *exit;
- list_for_each_entry_safe(bb, tmp, bbs, l) {
+ bb = entry_bb(bbs);
+ exit = exit_bb(bbs);
+ list_for_each_entry_safe_from(bb, tmp, &exit->l, l) {
+ subprog_free_edge(bb);
list_del(&bb->l);
kfree(bb);
}
diff --git a/kernel/bpf/cfg.h b/kernel/bpf/cfg.h
index 4092145..7a9d5dd 100644
--- a/kernel/bpf/cfg.h
+++ b/kernel/bpf/cfg.h
@@ -8,6 +8,7 @@
#ifndef __BPF_CFG_H__
#define __BPF_CFG_H__
+int subprog_add_bb_edges(struct bpf_insn *insns, struct list_head *bb_list);
int subprog_append_bb(struct list_head *bb_list, int head);
int subprog_fini_bb(struct list_head *bb_list, int subprog_end);
int subprog_init_bb(struct list_head *bb_list, int subprog_start);
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 523e440..bcac7c8 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -900,6 +900,9 @@ static int check_subprogs(struct bpf_verifier_env *env)
ret = subprog_fini_bb(cur_bb_list, subprog_end);
if (ret < 0)
goto free_nodes;
+ ret = subprog_add_bb_edges(insn, cur_bb_list);
+ if (ret < 0)
+ goto free_nodes;
subprog_start = subprog_end;
cur_subprog++;
if (cur_subprog < env->subprog_cnt) {
^ permalink raw reply related
* [RFC PATCH 03/16] bpf: cfg: build domination tree using Tarjan algorithm
From: John Fastabend @ 2018-06-01 9:32 UTC (permalink / raw)
To: alexei.starovoitov, daniel, davem; +Cc: netdev
In-Reply-To: <20180601092646.15353.28269.stgit@john-Precision-Tower-5810>
From: Jiong Wang <jiong.wang@netronome.com>
- When building domination information, we need to some array data
structure, and need to index into them using basic block index.
Calculate the basic block index during adding edges.
- The Step-1 in Tarjan algorithm is to assign dfs order number for
each bb in the cfg. We need to iterate on all bbs in reverse dfs order.
- Step-2 and Step-3 in Tarjan algorithm to calculate semi-dominators and
immediate-dominators implicitly and explicitly.
- Step-4, we add a new bitmap field inside subprog_info to keep the
dominator tree there.
- Post-domination information is built but not tested.
Signed-off-by: Jiong Wang <jiong.wang@netronome.com>
Signed-off-by: John Fastabend <john.fastabend@gmail.com>
---
include/linux/bpf_verifier.h | 3
kernel/bpf/cfg.c | 386 ++++++++++++++++++++++++++++++++++++++++++
kernel/bpf/cfg.h | 3
kernel/bpf/verifier.c | 5 -
4 files changed, 393 insertions(+), 4 deletions(-)
diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h
index c70faf5..0eb838d 100644
--- a/include/linux/bpf_verifier.h
+++ b/include/linux/bpf_verifier.h
@@ -178,6 +178,9 @@ struct bpf_subprog_info {
u32 start; /* insn idx of function entry point */
u16 stack_depth; /* max. stack depth used by this function */
struct list_head bbs; /* basic blocks list. */
+ u32 bb_num; /* total basic block num. */
+ unsigned long *dtree;
+ bool dtree_avail;
};
/* single container for all structs
diff --git a/kernel/bpf/cfg.c b/kernel/bpf/cfg.c
index 208aac7..b50937a 100644
--- a/kernel/bpf/cfg.c
+++ b/kernel/bpf/cfg.c
@@ -17,11 +17,33 @@ struct edge_node {
struct bb_node *dst;
};
+struct edge_iter {
+ struct list_head *list_head;
+ struct edge_node *edge;
+};
+
+#define first_edge(e_list) list_first_entry(e_list, struct edge_node, l)
+#define last_edge(e_list) list_last_entry(e_list, struct edge_node, l)
+#define next_edge(e) list_next_entry(e, l)
+
+static bool ei_end_p(struct edge_iter *ei)
+{
+ return &ei->edge->l == ei->list_head;
+}
+
+static void ei_next(struct edge_iter *ei)
+{
+ struct edge_node *e = ei->edge;
+
+ ei->edge = next_edge(e);
+}
+
struct bb_node {
struct list_head l;
struct list_head e_prevs;
struct list_head e_succs;
u16 head;
+ u16 idx;
};
#define bb_prev(bb) list_prev_entry(bb, l)
@@ -31,6 +53,27 @@ struct bb_node {
#define entry_bb(bb_list) bb_first(bb_list)
#define exit_bb(bb_list) bb_last(bb_list)
+struct dom_info {
+ u16 *dfs_parent;
+ u16 *dfs_order;
+ struct bb_node **dfs_to_bb;
+ /* immediate-dominator */
+ u16 *idom;
+ /* semi-dominator */
+ u16 *sdom;
+ u16 *bucket;
+ u16 *next_bucket;
+ /* best node during path compression. */
+ u16 *best;
+ /* ancestor along tree edge. */
+ u16 *ancestor;
+ /* size and child are used for tree balancing. */
+ u16 *size;
+ u16 *child;
+
+ u16 dfsnum;
+};
+
int subprog_append_bb(struct list_head *bb_list, int head)
{
struct bb_node *new_bb, *bb;
@@ -107,6 +150,7 @@ int subprog_add_bb_edges(struct bpf_insn *insns, struct list_head *bb_list)
{
struct bb_node *bb, *exit_bb;
struct edge_node *edge;
+ int bb_num;
bb = entry_bb(bb_list);
edge = kcalloc(2, sizeof(*edge), GFP_KERNEL);
@@ -118,9 +162,12 @@ int subprog_add_bb_edges(struct bpf_insn *insns, struct list_head *bb_list)
edge[1].src = edge->src;
edge[1].dst = edge->dst;
list_add_tail(&edge[1].l, &edge[1].dst->e_prevs);
+ bb->idx = -1;
exit_bb = exit_bb(bb_list);
+ exit_bb->idx = -2;
bb = bb_next(bb);
+ bb_num = 0;
list_for_each_entry_from(bb, &exit_bb->l, l) {
bool has_fallthrough, only_has_fallthrough;
bool has_branch, only_has_branch;
@@ -129,6 +176,8 @@ int subprog_add_bb_edges(struct bpf_insn *insns, struct list_head *bb_list)
struct bpf_insn insn;
u8 code;
+ bb->idx = bb_num++;
+
edge = kcalloc(2, sizeof(*edge), GFP_KERNEL);
if (!edge)
return -ENOMEM;
@@ -184,9 +233,341 @@ int subprog_add_bb_edges(struct bpf_insn *insns, struct list_head *bb_list)
}
}
+ return bb_num + 2;
+}
+
+static int init_dom_info(struct bpf_subprog_info *subprog, struct dom_info *di)
+{
+ u16 *p, bb_num, i;
+
+ di->dfs_parent = NULL;
+ di->dfs_to_bb = NULL;
+
+ bb_num = subprog->bb_num;
+ p = kcalloc(10 * bb_num, sizeof(*p), GFP_KERNEL);
+ if (!p)
+ return -ENOMEM;
+
+ di->dfs_parent = p;
+ di->dfs_order = di->dfs_parent + bb_num;
+ di->idom = di->dfs_order + bb_num;
+ di->sdom = di->idom + bb_num;
+ di->bucket = di->sdom + bb_num;
+ di->next_bucket = di->bucket + bb_num;
+ di->best = di->next_bucket + bb_num;
+ di->ancestor = di->best + bb_num;
+ di->size = di->ancestor + bb_num;
+ di->child = di->size + bb_num;
+ di->dfs_to_bb = kcalloc(bb_num, sizeof(struct bb_node *), GFP_KERNEL);
+ di->dfsnum = 1;
+
+ for (i = 0; i < bb_num; i++) {
+ di->size[i] = 1;
+ di->best[i] = i;
+ di->sdom[i] = i;
+ }
+
return 0;
}
+static void compress_path(struct dom_info *di, unsigned int v)
+{
+ unsigned int parent = di->ancestor[v];
+
+ if (di->ancestor[parent]) {
+ compress_path(di, parent);
+
+ if (di->sdom[di->best[parent]] < di->sdom[di->best[v]])
+ di->best[v] = di->best[parent];
+
+ di->ancestor[v] = di->ancestor[parent];
+ }
+}
+
+static unsigned int eval(struct dom_info *di, unsigned int v)
+{
+ unsigned int ancestor = di->ancestor[v];
+
+ /* v is root. */
+ if (!ancestor)
+ return di->best[v];
+
+ /* compress path */
+ compress_path(di, v);
+ ancestor = di->ancestor[v];
+
+ if (di->sdom[di->best[ancestor]] >= di->sdom[di->best[v]])
+ return di->best[v];
+ else
+ return di->best[ancestor];
+}
+
+/* Re-balancing the tree before linking. */
+static void link(struct dom_info *di, unsigned int v, unsigned int w)
+{
+ unsigned int s = w;
+
+ while (di->sdom[di->best[w]] < di->sdom[di->best[di->child[s]]]) {
+ if (di->size[s] + di->size[di->child[di->child[s]]] >=
+ 2 * di->size[di->child[s]]) {
+ di->ancestor[di->child[s]] = s;
+ di->child[s] = di->child[di->child[s]];
+ } else {
+ di->size[di->child[s]] = di->size[s];
+ di->ancestor[s] = di->child[s];
+ s = di->child[s];
+ }
+ }
+
+ di->best[s] = di->best[w];
+ di->size[v] += di->size[w];
+ if (di->size[v] < 2 * di->size[w]) {
+ unsigned int t = s;
+
+ s = di->child[v];
+ di->child[v] = t;
+ }
+
+ while (s) {
+ di->ancestor[s] = v;
+ s = di->child[s];
+ }
+}
+
+static void calc_idoms(struct bpf_subprog_info *subprog, struct dom_info *di,
+ bool reverse)
+{
+ u16 entry_bb_fake_idx = subprog->bb_num - 2, idx, w, k, par;
+ struct list_head *bb_list = &subprog->bbs;
+ struct bb_node *entry_bb;
+ struct edge_iter ei;
+
+ if (reverse)
+ entry_bb = exit_bb(bb_list);
+ else
+ entry_bb = entry_bb(bb_list);
+ idx = di->dfsnum - 1;
+
+ while (idx > 1) {
+ struct bb_node *bb = di->dfs_to_bb[idx];
+ struct edge_node *e;
+
+ par = di->dfs_parent[idx];
+ k = idx;
+
+ if (reverse) {
+ ei.edge = first_edge(&bb->e_succs);
+ ei.list_head = &bb->e_succs;
+ } else {
+ ei.edge = first_edge(&bb->e_prevs);
+ ei.list_head = &bb->e_prevs;
+ }
+
+ while (!ei_end_p(&ei)) {
+ struct bb_node *b;
+ u16 k1;
+
+ e = ei.edge;
+ if (reverse)
+ b = e->dst;
+ else
+ b = e->src;
+ ei_next(&ei);
+
+ if (b == entry_bb)
+ k1 = di->dfs_order[entry_bb_fake_idx];
+ else
+ k1 = di->dfs_order[b->idx];
+
+ if (k1 > idx)
+ k1 = di->sdom[eval(di, k1)];
+ if (k1 < k)
+ k = k1;
+ }
+
+ di->sdom[idx] = k;
+ link(di, par, idx);
+ di->next_bucket[idx] = di->bucket[k];
+ di->bucket[k] = idx;
+
+ for (w = di->bucket[par]; w; w = di->next_bucket[w]) {
+ k = eval(di, w);
+ if (di->sdom[k] < di->sdom[w])
+ di->idom[w] = k;
+ else
+ di->idom[w] = par;
+ }
+ di->bucket[par] = 0;
+ idx--;
+ }
+
+ di->idom[1] = 0;
+ for (idx = 2; idx <= di->dfsnum - 1; idx++)
+ if (di->idom[idx] != di->sdom[idx])
+ di->idom[idx] = di->idom[di->idom[idx]];
+}
+
+static int calc_dfs_tree(struct bpf_subprog_info *subprog, struct dom_info *di,
+ bool reverse)
+{
+ u16 bb_num = subprog->bb_num, sp = 0, idx, parent_idx;
+ struct list_head *bb_list = &subprog->bbs;
+ u16 entry_bb_fake_idx = bb_num - 2;
+ struct bb_node *entry_bb, *exit_bb;
+ struct edge_iter ei, *stack;
+ struct edge_node *e;
+
+ di->dfs_order[entry_bb_fake_idx] = di->dfsnum;
+
+ stack = kmalloc_array(bb_num - 1, sizeof(struct edge_iter), GFP_KERNEL);
+ if (!stack)
+ return -ENOMEM;
+
+ if (reverse) {
+ entry_bb = exit_bb(bb_list);
+ exit_bb = entry_bb(bb_list);
+ di->dfs_to_bb[di->dfsnum++] = exit_bb;
+ ei.edge = first_edge(&entry_bb->e_prevs);
+ ei.list_head = &entry_bb->e_prevs;
+ } else {
+ entry_bb = entry_bb(bb_list);
+ exit_bb = exit_bb(bb_list);
+ di->dfs_to_bb[di->dfsnum++] = entry_bb;
+ ei.edge = first_edge(&entry_bb->e_succs);
+ ei.list_head = &entry_bb->e_succs;
+ }
+
+ while (1) {
+ struct bb_node *bb_dst, *bb_src;
+
+ while (!ei_end_p(&ei)) {
+ e = ei.edge;
+
+ if (reverse) {
+ bb_dst = e->src;
+ if (bb_dst == exit_bb ||
+ di->dfs_order[bb_dst->idx]) {
+ ei_next(&ei);
+ continue;
+ }
+ bb_src = e->dst;
+ } else {
+ bb_dst = e->dst;
+ if (bb_dst == exit_bb ||
+ di->dfs_order[bb_dst->idx]) {
+ ei_next(&ei);
+ continue;
+ }
+ bb_src = e->src;
+ }
+
+ if (bb_src != entry_bb)
+ parent_idx = di->dfs_order[bb_src->idx];
+ else
+ parent_idx = di->dfs_order[entry_bb_fake_idx];
+
+ idx = di->dfsnum++;
+ di->dfs_order[bb_dst->idx] = idx;
+ di->dfs_to_bb[idx] = bb_dst;
+ di->dfs_parent[idx] = parent_idx;
+
+ stack[sp++] = ei;
+ if (reverse) {
+ ei.edge = first_edge(&bb_dst->e_prevs);
+ ei.list_head = &bb_dst->e_prevs;
+ } else {
+ ei.edge = first_edge(&bb_dst->e_succs);
+ ei.list_head = &bb_dst->e_succs;
+ }
+ }
+
+ if (!sp)
+ break;
+
+ ei = stack[--sp];
+ ei_next(&ei);
+ }
+
+ kfree(stack);
+
+ return 0;
+}
+
+static int idoms_to_doms(struct bpf_subprog_info *subprog, struct dom_info *di)
+{
+ int bb_num, i, end_index, bb, bb_idom, lane_len;
+ unsigned long *bitmap;
+
+ bb_num = subprog->bb_num - 2;
+ lane_len = BITS_TO_LONGS(bb_num);
+ bitmap = kcalloc(bb_num, lane_len * sizeof(long), GFP_KERNEL);
+ subprog->dtree = bitmap;
+ if (!subprog->dtree)
+ return -ENOMEM;
+ subprog->dtree_avail = true;
+ end_index = di->dfs_order[bb_num];
+
+ for (i = 1; i <= di->dfsnum - 1; i++) {
+ if (i == end_index)
+ continue;
+
+ bb = di->dfs_to_bb[i]->idx;
+ if (di->idom[i] && di->idom[i] != end_index) {
+ bb_idom = di->dfs_to_bb[di->idom[i]]->idx;
+ bitmap_copy(bitmap + bb * lane_len,
+ bitmap + bb_idom * lane_len, bb_num);
+ }
+
+ bitmap_set(bitmap + bb * lane_len, bb, 1);
+ }
+
+ return 0;
+}
+
+/* Build domination information using Lengauer and Tarjan algorithm.
+ *
+ * 1. dfs on cfg to assign dfs-num for each node(bb).
+ * 2. calculate semi-dominator and calculate immediate dominator when
+ * possible.
+ * 3. calculate immediate dominator not finished during step 2.
+ * 4. build domination bitmap using immediate dominator information.
+ *
+ * See:
+ * A fast algorithm for finding dominators in a flowgraph.
+ * - 1979, by T Lengauer and R Tarjan
+ *
+ * Especially, Appendix B: The Complete Dominators Algorithms.
+ *
+ * The implementation also referenced GNU GCC 3.0.
+ */
+
+int subprog_build_dom_info(struct bpf_subprog_info *subprog)
+{
+ struct dom_info di;
+ int ret;
+
+ ret = init_dom_info(subprog, &di);
+ if (ret < 0)
+ goto free_dominfo;
+
+ ret = calc_dfs_tree(subprog, &di, false);
+ if (ret < 0)
+ goto free_dominfo;
+
+ calc_idoms(subprog, &di, false);
+ ret = idoms_to_doms(subprog, &di);
+ if (ret < 0)
+ goto free_dominfo;
+
+ ret = 0;
+
+free_dominfo:
+ if (di.dfs_parent)
+ kfree(di.dfs_parent);
+
+ return ret;
+}
+
static void subprog_free_edge(struct bb_node *bb)
{
struct list_head *succs = &bb->e_succs;
@@ -199,7 +580,7 @@ static void subprog_free_edge(struct bb_node *bb)
}
}
-void subprog_free_bb(struct bpf_subprog_info *subprog, int end_idx)
+void subprog_free(struct bpf_subprog_info *subprog, int end_idx)
{
int i = 0;
@@ -214,5 +595,8 @@ void subprog_free_bb(struct bpf_subprog_info *subprog, int end_idx)
list_del(&bb->l);
kfree(bb);
}
+
+ if (subprog[i].dtree_avail)
+ kfree(subprog[i].dtree);
}
}
diff --git a/kernel/bpf/cfg.h b/kernel/bpf/cfg.h
index 7a9d5dd..cbb44f2 100644
--- a/kernel/bpf/cfg.h
+++ b/kernel/bpf/cfg.h
@@ -10,8 +10,9 @@
int subprog_add_bb_edges(struct bpf_insn *insns, struct list_head *bb_list);
int subprog_append_bb(struct list_head *bb_list, int head);
+int subprog_build_dom_info(struct bpf_subprog_info *subprog);
int subprog_fini_bb(struct list_head *bb_list, int subprog_end);
int subprog_init_bb(struct list_head *bb_list, int subprog_start);
-void subprog_free_bb(struct bpf_subprog_info *subprog, int end_idx);
+void subprog_free(struct bpf_subprog_info *subprog, int end_idx);
#endif
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index bcac7c8..eccaee4 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -903,6 +903,7 @@ static int check_subprogs(struct bpf_verifier_env *env)
ret = subprog_add_bb_edges(insn, cur_bb_list);
if (ret < 0)
goto free_nodes;
+ subprog[cur_subprog].bb_num = ret;
subprog_start = subprog_end;
cur_subprog++;
if (cur_subprog < env->subprog_cnt) {
@@ -919,8 +920,8 @@ static int check_subprogs(struct bpf_verifier_env *env)
ret = 0;
free_nodes:
- subprog_free_bb(subprog, cur_subprog == env->subprog_cnt ?
- cur_subprog - 1 : cur_subprog);
+ subprog_free(subprog, cur_subprog == env->subprog_cnt ?
+ cur_subprog - 1 : cur_subprog);
return ret;
}
^ permalink raw reply related
* [RFC PATCH 04/16] bpf: cfg: detect loop use domination information
From: John Fastabend @ 2018-06-01 9:32 UTC (permalink / raw)
To: alexei.starovoitov, daniel, davem; +Cc: netdev
In-Reply-To: <20180601092646.15353.28269.stgit@john-Precision-Tower-5810>
From: Jiong Wang <jiong.wang@netronome.com>
If one bb is dominating its predecessor, then there is loop.
Signed-off-by: Jiong Wang <jiong.wang@netronome.com>
Signed-off-by: John Fastabend <john.fastabend@gmail.com>
---
kernel/bpf/cfg.c | 22 ++++++++++++++++++++++
kernel/bpf/cfg.h | 1 +
kernel/bpf/verifier.c | 8 ++++++++
3 files changed, 31 insertions(+)
diff --git a/kernel/bpf/cfg.c b/kernel/bpf/cfg.c
index b50937a..90692e4 100644
--- a/kernel/bpf/cfg.c
+++ b/kernel/bpf/cfg.c
@@ -568,6 +568,28 @@ int subprog_build_dom_info(struct bpf_subprog_info *subprog)
return ret;
}
+bool subprog_has_loop(struct bpf_subprog_info *subprog)
+{
+ int lane_len = BITS_TO_LONGS(subprog->bb_num - 2);
+ struct list_head *bb_list = &subprog->bbs;
+ struct bb_node *bb, *entry_bb;
+ struct edge_node *e;
+
+ entry_bb = entry_bb(bb_list);
+ bb = bb_next(entry_bb);
+ list_for_each_entry_from(bb, &exit_bb(bb_list)->l, l)
+ list_for_each_entry(e, &bb->e_prevs, l) {
+ struct bb_node *latch = e->src;
+
+ if (latch != entry_bb &&
+ test_bit(bb->idx,
+ subprog->dtree + latch->idx * lane_len))
+ return true;
+ }
+
+ return false;
+}
+
static void subprog_free_edge(struct bb_node *bb)
{
struct list_head *succs = &bb->e_succs;
diff --git a/kernel/bpf/cfg.h b/kernel/bpf/cfg.h
index cbb44f2..c02c4cf 100644
--- a/kernel/bpf/cfg.h
+++ b/kernel/bpf/cfg.h
@@ -12,6 +12,7 @@
int subprog_append_bb(struct list_head *bb_list, int head);
int subprog_build_dom_info(struct bpf_subprog_info *subprog);
int subprog_fini_bb(struct list_head *bb_list, int subprog_end);
+bool subprog_has_loop(struct bpf_subprog_info *subprog);
int subprog_init_bb(struct list_head *bb_list, int subprog_start);
void subprog_free(struct bpf_subprog_info *subprog, int end_idx);
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index eccaee4..c349c45 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -904,6 +904,14 @@ static int check_subprogs(struct bpf_verifier_env *env)
if (ret < 0)
goto free_nodes;
subprog[cur_subprog].bb_num = ret;
+ ret = subprog_build_dom_info(&subprog[cur_subprog]);
+ if (ret < 0)
+ goto free_nodes;
+ if (subprog_has_loop(&subprog[cur_subprog])) {
+ verbose(env, "cfg - loop detected");
+ ret = -EINVAL;
+ goto free_nodes;
+ }
subprog_start = subprog_end;
cur_subprog++;
if (cur_subprog < env->subprog_cnt) {
^ permalink raw reply related
* [RFC PATCH 05/16] bpf: cfg: detect unreachable basic blocks
From: John Fastabend @ 2018-06-01 9:32 UTC (permalink / raw)
To: alexei.starovoitov, daniel, davem; +Cc: netdev
In-Reply-To: <20180601092646.15353.28269.stgit@john-Precision-Tower-5810>
From: Jiong Wang <jiong.wang@netronome.com>
Do unreachable basic blocks detection as a side-product of the dfs walk
when building domination information.
Signed-off-by: Jiong Wang <jiong.wang@netronome.com>
Signed-off-by: John Fastabend <john.fastabend@gmail.com>
---
kernel/bpf/cfg.c | 19 ++++++++++++++-----
kernel/bpf/cfg.h | 3 ++-
kernel/bpf/verifier.c | 3 ++-
3 files changed, 18 insertions(+), 7 deletions(-)
diff --git a/kernel/bpf/cfg.c b/kernel/bpf/cfg.c
index 90692e4..2f0ac00 100644
--- a/kernel/bpf/cfg.c
+++ b/kernel/bpf/cfg.c
@@ -407,10 +407,11 @@ static void calc_idoms(struct bpf_subprog_info *subprog, struct dom_info *di,
di->idom[idx] = di->idom[di->idom[idx]];
}
-static int calc_dfs_tree(struct bpf_subprog_info *subprog, struct dom_info *di,
- bool reverse)
+static int
+calc_dfs_tree(struct bpf_verifier_env *env, struct bpf_subprog_info *subprog,
+ struct dom_info *di, bool reverse)
{
- u16 bb_num = subprog->bb_num, sp = 0, idx, parent_idx;
+ u16 bb_num = subprog->bb_num, sp = 0, idx, parent_idx, i;
struct list_head *bb_list = &subprog->bbs;
u16 entry_bb_fake_idx = bb_num - 2;
struct bb_node *entry_bb, *exit_bb;
@@ -490,6 +491,13 @@ static int calc_dfs_tree(struct bpf_subprog_info *subprog, struct dom_info *di,
kfree(stack);
+ for (i = 0; i < bb_num - 2; i++) {
+ if (!di->dfs_order[i]) {
+ bpf_verifier_log_write(env, "cfg - unreachable insn\n");
+ return -EINVAL;
+ }
+ }
+
return 0;
}
@@ -541,7 +549,8 @@ static int idoms_to_doms(struct bpf_subprog_info *subprog, struct dom_info *di)
* The implementation also referenced GNU GCC 3.0.
*/
-int subprog_build_dom_info(struct bpf_subprog_info *subprog)
+int subprog_build_dom_info(struct bpf_verifier_env *env,
+ struct bpf_subprog_info *subprog)
{
struct dom_info di;
int ret;
@@ -550,7 +559,7 @@ int subprog_build_dom_info(struct bpf_subprog_info *subprog)
if (ret < 0)
goto free_dominfo;
- ret = calc_dfs_tree(subprog, &di, false);
+ ret = calc_dfs_tree(env, subprog, &di, false);
if (ret < 0)
goto free_dominfo;
diff --git a/kernel/bpf/cfg.h b/kernel/bpf/cfg.h
index c02c4cf..02729a9 100644
--- a/kernel/bpf/cfg.h
+++ b/kernel/bpf/cfg.h
@@ -10,7 +10,8 @@
int subprog_add_bb_edges(struct bpf_insn *insns, struct list_head *bb_list);
int subprog_append_bb(struct list_head *bb_list, int head);
-int subprog_build_dom_info(struct bpf_subprog_info *subprog);
+int subprog_build_dom_info(struct bpf_verifier_env *env,
+ struct bpf_subprog_info *subprog);
int subprog_fini_bb(struct list_head *bb_list, int subprog_end);
bool subprog_has_loop(struct bpf_subprog_info *subprog);
int subprog_init_bb(struct list_head *bb_list, int subprog_start);
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index c349c45..29797d2 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -904,7 +904,8 @@ static int check_subprogs(struct bpf_verifier_env *env)
if (ret < 0)
goto free_nodes;
subprog[cur_subprog].bb_num = ret;
- ret = subprog_build_dom_info(&subprog[cur_subprog]);
+ ret = subprog_build_dom_info(env,
+ &subprog[cur_subprog]);
if (ret < 0)
goto free_nodes;
if (subprog_has_loop(&subprog[cur_subprog])) {
^ permalink raw reply related
* [RFC PATCH 06/16] bpf: cfg: move find_subprog/add_subprog to cfg.c
From: John Fastabend @ 2018-06-01 9:32 UTC (permalink / raw)
To: alexei.starovoitov, daniel, davem; +Cc: netdev
In-Reply-To: <20180601092646.15353.28269.stgit@john-Precision-Tower-5810>
From: Jiong Wang <jiong.wang@netronome.com>
This patch centre find_subprog and add_subprog to cfg.c.
Signed-off-by: Jiong Wang <jiong.wang@netronome.com>
Signed-off-by: John Fastabend <john.fastabend@gmail.com>
---
kernel/bpf/cfg.c | 41 +++++++++++++++++++++++++++++++++++++++++
kernel/bpf/cfg.h | 2 ++
kernel/bpf/verifier.c | 42 ------------------------------------------
3 files changed, 43 insertions(+), 42 deletions(-)
diff --git a/kernel/bpf/cfg.c b/kernel/bpf/cfg.c
index 2f0ac00..5175aa7 100644
--- a/kernel/bpf/cfg.c
+++ b/kernel/bpf/cfg.c
@@ -6,8 +6,10 @@
*/
#include <linux/bpf_verifier.h>
+#include <linux/bsearch.h>
#include <linux/list.h>
#include <linux/slab.h>
+#include <linux/sort.h>
#include "cfg.h"
@@ -599,6 +601,45 @@ bool subprog_has_loop(struct bpf_subprog_info *subprog)
return false;
}
+static int cmp_subprogs(const void *a, const void *b)
+{
+ return ((struct bpf_subprog_info *)a)->start -
+ ((struct bpf_subprog_info *)b)->start;
+}
+
+int find_subprog(struct bpf_verifier_env *env, int off)
+{
+ struct bpf_subprog_info *p;
+
+ p = bsearch(&off, env->subprog_info, env->subprog_cnt,
+ sizeof(env->subprog_info[0]), cmp_subprogs);
+ if (!p)
+ return -ENOENT;
+ return p - env->subprog_info;
+}
+
+int add_subprog(struct bpf_verifier_env *env, int off)
+{
+ int insn_cnt = env->prog->len;
+ int ret;
+
+ if (off >= insn_cnt || off < 0) {
+ bpf_verifier_log_write(env, "call to invalid destination\n");
+ return -EINVAL;
+ }
+ ret = find_subprog(env, off);
+ if (ret >= 0)
+ return 0;
+ if (env->subprog_cnt >= BPF_MAX_SUBPROGS) {
+ bpf_verifier_log_write(env, "too many subprograms\n");
+ return -E2BIG;
+ }
+ env->subprog_info[env->subprog_cnt++].start = off;
+ sort(env->subprog_info, env->subprog_cnt,
+ sizeof(env->subprog_info[0]), cmp_subprogs, NULL);
+ return 0;
+}
+
static void subprog_free_edge(struct bb_node *bb)
{
struct list_head *succs = &bb->e_succs;
diff --git a/kernel/bpf/cfg.h b/kernel/bpf/cfg.h
index 02729a9..57eab9b 100644
--- a/kernel/bpf/cfg.h
+++ b/kernel/bpf/cfg.h
@@ -8,6 +8,8 @@
#ifndef __BPF_CFG_H__
#define __BPF_CFG_H__
+int add_subprog(struct bpf_verifier_env *env, int off);
+int find_subprog(struct bpf_verifier_env *env, int off);
int subprog_add_bb_edges(struct bpf_insn *insns, struct list_head *bb_list);
int subprog_append_bb(struct list_head *bb_list, int head);
int subprog_build_dom_info(struct bpf_verifier_env *env,
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 29797d2..782dd17 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -20,8 +20,6 @@
#include <linux/file.h>
#include <linux/vmalloc.h>
#include <linux/stringify.h>
-#include <linux/bsearch.h>
-#include <linux/sort.h>
#include <linux/perf_event.h>
#include "cfg.h"
@@ -762,46 +760,6 @@ enum reg_arg_type {
DST_OP_NO_MARK /* same as above, check only, don't mark */
};
-static int cmp_subprogs(const void *a, const void *b)
-{
- return ((struct bpf_subprog_info *)a)->start -
- ((struct bpf_subprog_info *)b)->start;
-}
-
-static int find_subprog(struct bpf_verifier_env *env, int off)
-{
- struct bpf_subprog_info *p;
-
- p = bsearch(&off, env->subprog_info, env->subprog_cnt,
- sizeof(env->subprog_info[0]), cmp_subprogs);
- if (!p)
- return -ENOENT;
- return p - env->subprog_info;
-
-}
-
-static int add_subprog(struct bpf_verifier_env *env, int off)
-{
- int insn_cnt = env->prog->len;
- int ret;
-
- if (off >= insn_cnt || off < 0) {
- verbose(env, "call to invalid destination\n");
- return -EINVAL;
- }
- ret = find_subprog(env, off);
- if (ret >= 0)
- return 0;
- if (env->subprog_cnt >= BPF_MAX_SUBPROGS) {
- verbose(env, "too many subprograms\n");
- return -E2BIG;
- }
- env->subprog_info[env->subprog_cnt++].start = off;
- sort(env->subprog_info, env->subprog_cnt,
- sizeof(env->subprog_info[0]), cmp_subprogs, NULL);
- return 0;
-}
-
static int check_subprogs(struct bpf_verifier_env *env)
{
int i, ret, subprog_start, subprog_end, off, cur_subprog = 0;
^ permalink raw reply related
* [RFC PATCH 07/16] bpf: cfg: build call graph and detect unreachable/recursive call
From: John Fastabend @ 2018-06-01 9:32 UTC (permalink / raw)
To: alexei.starovoitov, daniel, davem; +Cc: netdev
In-Reply-To: <20180601092646.15353.28269.stgit@john-Precision-Tower-5810>
From: Jiong Wang <jiong.wang@netronome.com>
This patch build call graph during insn scan inside check_subprogs.
Then do recursive and unreachable subprog detection using call graph.
Signed-off-by: Jiong Wang <jiong.wang@netronome.com>
Signed-off-by: John Fastabend <john.fastabend@gmail.com>
---
include/linux/bpf_verifier.h | 1
kernel/bpf/cfg.c | 133 ++++++++++++++++++++++++++++++++++++++++++
kernel/bpf/cfg.h | 4 +
kernel/bpf/verifier.c | 32 +++++++++-
4 files changed, 166 insertions(+), 4 deletions(-)
diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h
index 0eb838d..83ccbc4 100644
--- a/include/linux/bpf_verifier.h
+++ b/include/linux/bpf_verifier.h
@@ -177,6 +177,7 @@ static inline bool bpf_verifier_log_needed(const struct bpf_verifier_log *log)
struct bpf_subprog_info {
u32 start; /* insn idx of function entry point */
u16 stack_depth; /* max. stack depth used by this function */
+ struct list_head callees; /* callees list. */
struct list_head bbs; /* basic blocks list. */
u32 bb_num; /* total basic block num. */
unsigned long *dtree;
diff --git a/kernel/bpf/cfg.c b/kernel/bpf/cfg.c
index 5175aa7..56c08e8 100644
--- a/kernel/bpf/cfg.c
+++ b/kernel/bpf/cfg.c
@@ -13,6 +13,12 @@
#include "cfg.h"
+struct cedge_node {
+ struct list_head l;
+ u8 caller_idx;
+ u8 callee_idx;
+};
+
struct edge_node {
struct list_head l;
struct bb_node *src;
@@ -640,6 +646,126 @@ int add_subprog(struct bpf_verifier_env *env, int off)
return 0;
}
+struct callee_iter {
+ struct list_head *list_head;
+ struct cedge_node *callee;
+};
+
+#define first_callee(c_list) list_first_entry(c_list, struct cedge_node, l)
+#define next_callee(c) list_next_entry(c, l)
+
+static bool ci_end_p(struct callee_iter *ci)
+{
+ return &ci->callee->l == ci->list_head;
+}
+
+static void ci_next(struct callee_iter *ci)
+{
+ struct cedge_node *c = ci->callee;
+
+ ci->callee = next_callee(c);
+}
+
+#define EXPLORING 1
+#define EXPLORED 2
+int cgraph_check_recursive_unreachable(struct bpf_verifier_env *env,
+ struct bpf_subprog_info *subprog)
+{
+ struct callee_iter *stack;
+ struct cedge_node *callee;
+ int sp = 0, idx = 0, ret;
+ struct callee_iter ci;
+ int *status;
+
+ stack = kmalloc_array(128, sizeof(struct callee_iter), GFP_KERNEL);
+ if (!stack)
+ return -ENOMEM;
+ status = kcalloc(env->subprog_cnt, sizeof(int), GFP_KERNEL);
+ if (!status) {
+ kfree(stack);
+ return -ENOMEM;
+ }
+ ci.callee = first_callee(&subprog->callees);
+ ci.list_head = &subprog->callees;
+ status[0] = EXPLORING;
+
+ while (1) {
+ while (!ci_end_p(&ci)) {
+ callee = ci.callee;
+ idx = callee->callee_idx;
+ if (status[idx] == EXPLORING) {
+ bpf_verifier_log_write(env, "cgraph - recursive call\n");
+ ret = -EINVAL;
+ goto err_free;
+ }
+
+ status[idx] = EXPLORING;
+
+ if (sp == 127) {
+ bpf_verifier_log_write(env, "cgraph - call frame too deep\n");
+ ret = -EINVAL;
+ goto err_free;
+ }
+
+ stack[sp++] = ci;
+ ci.callee = first_callee(&subprog[idx].callees);
+ ci.list_head = &subprog[idx].callees;
+ }
+
+ if (!list_empty(ci.list_head))
+ status[first_callee(ci.list_head)->caller_idx] =
+ EXPLORED;
+ else
+ /* leaf func. */
+ status[idx] = EXPLORED;
+
+ if (!sp)
+ break;
+
+ ci = stack[--sp];
+ ci_next(&ci);
+ }
+
+ for (idx = 0; idx < env->subprog_cnt; idx++)
+ if (status[idx] != EXPLORED) {
+ bpf_verifier_log_write(env, "cgraph - unreachable subprog\n");
+ ret = -EINVAL;
+ goto err_free;
+ }
+
+ ret = 0;
+err_free:
+ kfree(status);
+ kfree(stack);
+ return ret;
+}
+
+int subprog_append_callee(struct bpf_verifier_env *env,
+ struct list_head *callees_list,
+ int caller_idx, int off)
+{
+ int callee_idx = find_subprog(env, off);
+ struct cedge_node *new_callee, *callee;
+
+ if (callee_idx < 0)
+ return callee_idx;
+
+ list_for_each_entry(callee, callees_list, l) {
+ if (callee->callee_idx == callee_idx)
+ return 0;
+ }
+
+ new_callee = kzalloc(sizeof(*new_callee), GFP_KERNEL);
+ if (!new_callee)
+ return -ENOMEM;
+
+ new_callee->caller_idx = caller_idx;
+ new_callee->callee_idx = callee_idx;
+ list_add_tail(&new_callee->l, callees_list);
+
+ return 0;
+}
+
static void subprog_free_edge(struct bb_node *bb)
{
struct list_head *succs = &bb->e_succs;
@@ -657,7 +783,9 @@ void subprog_free(struct bpf_subprog_info *subprog, int end_idx)
int i = 0;
for (; i <= end_idx; i++) {
+ struct list_head *callees = &subprog[i].callees;
struct list_head *bbs = &subprog[i].bbs;
+ struct cedge_node *callee, *tmp_callee;
struct bb_node *bb, *tmp, *exit;
bb = entry_bb(bbs);
@@ -668,6 +796,11 @@ void subprog_free(struct bpf_subprog_info *subprog, int end_idx)
kfree(bb);
}
+ list_for_each_entry_safe(callee, tmp_callee, callees, l) {
+ list_del(&callee->l);
+ kfree(callee);
+ }
+
if (subprog[i].dtree_avail)
kfree(subprog[i].dtree);
}
diff --git a/kernel/bpf/cfg.h b/kernel/bpf/cfg.h
index 57eab9b..577c22c 100644
--- a/kernel/bpf/cfg.h
+++ b/kernel/bpf/cfg.h
@@ -9,9 +9,13 @@
#define __BPF_CFG_H__
int add_subprog(struct bpf_verifier_env *env, int off);
+int cgraph_check_recursive_unreachable(struct bpf_verifier_env *env,
+ struct bpf_subprog_info *subprog);
int find_subprog(struct bpf_verifier_env *env, int off);
int subprog_add_bb_edges(struct bpf_insn *insns, struct list_head *bb_list);
int subprog_append_bb(struct list_head *bb_list, int head);
+int subprog_append_callee(struct bpf_verifier_env *env,
+ struct list_head *bb_list, int caller_idx, int off);
int subprog_build_dom_info(struct bpf_verifier_env *env,
struct bpf_subprog_info *subprog);
int subprog_fini_bb(struct list_head *bb_list, int subprog_end);
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 782dd17..ddba8ad 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -764,9 +764,9 @@ static int check_subprogs(struct bpf_verifier_env *env)
{
int i, ret, subprog_start, subprog_end, off, cur_subprog = 0;
struct bpf_subprog_info *subprog = env->subprog_info;
+ struct list_head *cur_bb_list, *cur_callee_list;
struct bpf_insn *insn = env->prog->insnsi;
int insn_cnt = env->prog->len;
- struct list_head *cur_bb_list;
/* Add entry function. */
ret = add_subprog(env, 0);
@@ -797,16 +797,23 @@ static int check_subprogs(struct bpf_verifier_env *env)
*/
subprog[env->subprog_cnt].start = insn_cnt;
- if (env->log.level > 1)
- for (i = 0; i < env->subprog_cnt; i++)
+ for (i = 0; i < env->subprog_cnt; i++) {
+ if (env->log.level > 1)
verbose(env, "func#%d @%d\n", i, subprog[i].start);
+ /* Don't init callees inside add_subprog which will sort the
+ * array which breaks list link.
+ */
+ INIT_LIST_HEAD(&subprog[i].callees);
+ }
+
subprog_start = subprog[cur_subprog].start;
subprog_end = subprog[cur_subprog + 1].start;
cur_bb_list = &subprog[cur_subprog].bbs;
ret = subprog_init_bb(cur_bb_list, subprog_start);
if (ret < 0)
goto free_nodes;
+ cur_callee_list = &env->subprog_info[cur_subprog].callees;
/* now check that all jumps are within the same subprog */
for (i = 0; i < insn_cnt; i++) {
u8 code = insn[i].code;
@@ -823,8 +830,20 @@ static int check_subprogs(struct bpf_verifier_env *env)
goto next;
}
- if (BPF_OP(code) == BPF_CALL)
+ if (BPF_OP(code) == BPF_CALL) {
+ if (insn[i].src_reg == BPF_PSEUDO_CALL) {
+ int target = i + insn[i].imm + 1;
+
+ ret = subprog_append_callee(env,
+ cur_callee_list,
+ cur_subprog,
+ target);
+ if (ret < 0)
+ return ret;
+ }
+
goto next;
+ }
off = i + insn[i].off + 1;
if (off < subprog_start || off >= subprog_end) {
@@ -880,10 +899,15 @@ static int check_subprogs(struct bpf_verifier_env *env)
subprog_start);
if (ret < 0)
goto free_nodes;
+ cur_callee_list = &subprog[cur_subprog].callees;
}
}
}
+ ret = cgraph_check_recursive_unreachable(env, env->subprog_info);
+ if (ret < 0)
+ goto free_nodes;
+
ret = 0;
free_nodes:
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox