diff options
-rw-r--r-- | drivers/infiniband/core/uverbs_cmd.c | 98 | ||||
-rw-r--r-- | include/rdma/ib_verbs.h | 10 |
2 files changed, 83 insertions, 25 deletions
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index 19c1ebf596ad..b9fb256c25fa 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c | |||
@@ -3078,51 +3078,98 @@ out_put: | |||
3078 | return ret ? ret : in_len; | 3078 | return ret ? ret : in_len; |
3079 | } | 3079 | } |
3080 | 3080 | ||
3081 | static size_t kern_spec_filter_sz(struct ib_uverbs_flow_spec_hdr *spec) | ||
3082 | { | ||
3083 | /* Returns user space filter size, includes padding */ | ||
3084 | return (spec->size - sizeof(struct ib_uverbs_flow_spec_hdr)) / 2; | ||
3085 | } | ||
3086 | |||
3087 | static ssize_t spec_filter_size(void *kern_spec_filter, u16 kern_filter_size, | ||
3088 | u16 ib_real_filter_sz) | ||
3089 | { | ||
3090 | /* | ||
3091 | * User space filter structures must be 64 bit aligned, otherwise this | ||
3092 | * may pass, but we won't handle additional new attributes. | ||
3093 | */ | ||
3094 | |||
3095 | if (kern_filter_size > ib_real_filter_sz) { | ||
3096 | if (memchr_inv(kern_spec_filter + | ||
3097 | ib_real_filter_sz, 0, | ||
3098 | kern_filter_size - ib_real_filter_sz)) | ||
3099 | return -EINVAL; | ||
3100 | return ib_real_filter_sz; | ||
3101 | } | ||
3102 | return kern_filter_size; | ||
3103 | } | ||
3104 | |||
3081 | static int kern_spec_to_ib_spec(struct ib_uverbs_flow_spec *kern_spec, | 3105 | static int kern_spec_to_ib_spec(struct ib_uverbs_flow_spec *kern_spec, |
3082 | union ib_flow_spec *ib_spec) | 3106 | union ib_flow_spec *ib_spec) |
3083 | { | 3107 | { |
3108 | ssize_t actual_filter_sz; | ||
3109 | ssize_t kern_filter_sz; | ||
3110 | ssize_t ib_filter_sz; | ||
3111 | void *kern_spec_mask; | ||
3112 | void *kern_spec_val; | ||
3113 | |||
3084 | if (kern_spec->reserved) | 3114 | if (kern_spec->reserved) |
3085 | return -EINVAL; | 3115 | return -EINVAL; |
3086 | 3116 | ||
3087 | ib_spec->type = kern_spec->type; | 3117 | ib_spec->type = kern_spec->type; |
3088 | 3118 | ||
3119 | kern_filter_sz = kern_spec_filter_sz(&kern_spec->hdr); | ||
3120 | /* User flow spec size must be aligned to 4 bytes */ | ||
3121 | if (kern_filter_sz != ALIGN(kern_filter_sz, 4)) | ||
3122 | return -EINVAL; | ||
3123 | |||
3124 | kern_spec_val = (void *)kern_spec + | ||
3125 | sizeof(struct ib_uverbs_flow_spec_hdr); | ||
3126 | kern_spec_mask = kern_spec_val + kern_filter_sz; | ||
3127 | |||
3089 | switch (ib_spec->type) { | 3128 | switch (ib_spec->type) { |
3090 | case IB_FLOW_SPEC_ETH: | 3129 | case IB_FLOW_SPEC_ETH: |
3091 | ib_spec->eth.size = sizeof(struct ib_flow_spec_eth); | 3130 | ib_filter_sz = offsetof(struct ib_flow_eth_filter, real_sz); |
3092 | if (ib_spec->eth.size != kern_spec->eth.size) | 3131 | actual_filter_sz = spec_filter_size(kern_spec_mask, |
3132 | kern_filter_sz, | ||
3133 | ib_filter_sz); | ||
3134 | if (actual_filter_sz <= 0) | ||
3093 | return -EINVAL; | 3135 | return -EINVAL; |
3094 | memcpy(&ib_spec->eth.val, &kern_spec->eth.val, | 3136 | ib_spec->size = sizeof(struct ib_flow_spec_eth); |
3095 | sizeof(struct ib_flow_eth_filter)); | 3137 | memcpy(&ib_spec->eth.val, kern_spec_val, actual_filter_sz); |
3096 | memcpy(&ib_spec->eth.mask, &kern_spec->eth.mask, | 3138 | memcpy(&ib_spec->eth.mask, kern_spec_mask, actual_filter_sz); |
3097 | sizeof(struct ib_flow_eth_filter)); | ||
3098 | break; | 3139 | break; |
3099 | case IB_FLOW_SPEC_IPV4: | 3140 | case IB_FLOW_SPEC_IPV4: |
3100 | ib_spec->ipv4.size = sizeof(struct ib_flow_spec_ipv4); | 3141 | ib_filter_sz = offsetof(struct ib_flow_ipv4_filter, real_sz); |
3101 | if (ib_spec->ipv4.size != kern_spec->ipv4.size) | 3142 | actual_filter_sz = spec_filter_size(kern_spec_mask, |
3143 | kern_filter_sz, | ||
3144 | ib_filter_sz); | ||
3145 | if (actual_filter_sz <= 0) | ||
3102 | return -EINVAL; | 3146 | return -EINVAL; |
3103 | memcpy(&ib_spec->ipv4.val, &kern_spec->ipv4.val, | 3147 | ib_spec->size = sizeof(struct ib_flow_spec_ipv4); |
3104 | sizeof(struct ib_flow_ipv4_filter)); | 3148 | memcpy(&ib_spec->ipv4.val, kern_spec_val, actual_filter_sz); |
3105 | memcpy(&ib_spec->ipv4.mask, &kern_spec->ipv4.mask, | 3149 | memcpy(&ib_spec->ipv4.mask, kern_spec_mask, actual_filter_sz); |
3106 | sizeof(struct ib_flow_ipv4_filter)); | ||
3107 | break; | 3150 | break; |
3108 | case IB_FLOW_SPEC_IPV6: | 3151 | case IB_FLOW_SPEC_IPV6: |
3109 | ib_spec->ipv6.size = sizeof(struct ib_flow_spec_ipv6); | 3152 | ib_filter_sz = offsetof(struct ib_flow_ipv6_filter, real_sz); |
3110 | if (ib_spec->ipv6.size != kern_spec->ipv6.size) | 3153 | actual_filter_sz = spec_filter_size(kern_spec_mask, |
3154 | kern_filter_sz, | ||
3155 | ib_filter_sz); | ||
3156 | if (actual_filter_sz <= 0) | ||
3111 | return -EINVAL; | 3157 | return -EINVAL; |
3112 | memcpy(&ib_spec->ipv6.val, &kern_spec->ipv6.val, | 3158 | ib_spec->size = sizeof(struct ib_flow_spec_ipv6); |
3113 | sizeof(struct ib_flow_ipv6_filter)); | 3159 | memcpy(&ib_spec->ipv6.val, kern_spec_val, actual_filter_sz); |
3114 | memcpy(&ib_spec->ipv6.mask, &kern_spec->ipv6.mask, | 3160 | memcpy(&ib_spec->ipv6.mask, kern_spec_mask, actual_filter_sz); |
3115 | sizeof(struct ib_flow_ipv6_filter)); | ||
3116 | break; | 3161 | break; |
3117 | case IB_FLOW_SPEC_TCP: | 3162 | case IB_FLOW_SPEC_TCP: |
3118 | case IB_FLOW_SPEC_UDP: | 3163 | case IB_FLOW_SPEC_UDP: |
3119 | ib_spec->tcp_udp.size = sizeof(struct ib_flow_spec_tcp_udp); | 3164 | ib_filter_sz = offsetof(struct ib_flow_tcp_udp_filter, real_sz); |
3120 | if (ib_spec->tcp_udp.size != kern_spec->tcp_udp.size) | 3165 | actual_filter_sz = spec_filter_size(kern_spec_mask, |
3166 | kern_filter_sz, | ||
3167 | ib_filter_sz); | ||
3168 | if (actual_filter_sz <= 0) | ||
3121 | return -EINVAL; | 3169 | return -EINVAL; |
3122 | memcpy(&ib_spec->tcp_udp.val, &kern_spec->tcp_udp.val, | 3170 | ib_spec->size = sizeof(struct ib_flow_spec_tcp_udp); |
3123 | sizeof(struct ib_flow_tcp_udp_filter)); | 3171 | memcpy(&ib_spec->tcp_udp.val, kern_spec_val, actual_filter_sz); |
3124 | memcpy(&ib_spec->tcp_udp.mask, &kern_spec->tcp_udp.mask, | 3172 | memcpy(&ib_spec->tcp_udp.mask, kern_spec_mask, actual_filter_sz); |
3125 | sizeof(struct ib_flow_tcp_udp_filter)); | ||
3126 | break; | 3173 | break; |
3127 | default: | 3174 | default: |
3128 | return -EINVAL; | 3175 | return -EINVAL; |
@@ -3654,7 +3701,8 @@ int ib_uverbs_ex_create_flow(struct ib_uverbs_file *file, | |||
3654 | goto err_uobj; | 3701 | goto err_uobj; |
3655 | } | 3702 | } |
3656 | 3703 | ||
3657 | flow_attr = kmalloc(sizeof(*flow_attr) + cmd.flow_attr.size, GFP_KERNEL); | 3704 | flow_attr = kzalloc(sizeof(*flow_attr) + cmd.flow_attr.num_of_specs * |
3705 | sizeof(union ib_flow_spec), GFP_KERNEL); | ||
3658 | if (!flow_attr) { | 3706 | if (!flow_attr) { |
3659 | err = -ENOMEM; | 3707 | err = -ENOMEM; |
3660 | goto err_put; | 3708 | goto err_put; |
diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index d74c76bf76d3..4570d8844f63 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h | |||
@@ -1623,6 +1623,8 @@ struct ib_flow_eth_filter { | |||
1623 | u8 src_mac[6]; | 1623 | u8 src_mac[6]; |
1624 | __be16 ether_type; | 1624 | __be16 ether_type; |
1625 | __be16 vlan_tag; | 1625 | __be16 vlan_tag; |
1626 | /* Must be last */ | ||
1627 | u8 real_sz[0]; | ||
1626 | }; | 1628 | }; |
1627 | 1629 | ||
1628 | struct ib_flow_spec_eth { | 1630 | struct ib_flow_spec_eth { |
@@ -1635,6 +1637,8 @@ struct ib_flow_spec_eth { | |||
1635 | struct ib_flow_ib_filter { | 1637 | struct ib_flow_ib_filter { |
1636 | __be16 dlid; | 1638 | __be16 dlid; |
1637 | __u8 sl; | 1639 | __u8 sl; |
1640 | /* Must be last */ | ||
1641 | u8 real_sz[0]; | ||
1638 | }; | 1642 | }; |
1639 | 1643 | ||
1640 | struct ib_flow_spec_ib { | 1644 | struct ib_flow_spec_ib { |
@@ -1647,6 +1651,8 @@ struct ib_flow_spec_ib { | |||
1647 | struct ib_flow_ipv4_filter { | 1651 | struct ib_flow_ipv4_filter { |
1648 | __be32 src_ip; | 1652 | __be32 src_ip; |
1649 | __be32 dst_ip; | 1653 | __be32 dst_ip; |
1654 | /* Must be last */ | ||
1655 | u8 real_sz[0]; | ||
1650 | }; | 1656 | }; |
1651 | 1657 | ||
1652 | struct ib_flow_spec_ipv4 { | 1658 | struct ib_flow_spec_ipv4 { |
@@ -1659,6 +1665,8 @@ struct ib_flow_spec_ipv4 { | |||
1659 | struct ib_flow_ipv6_filter { | 1665 | struct ib_flow_ipv6_filter { |
1660 | u8 src_ip[16]; | 1666 | u8 src_ip[16]; |
1661 | u8 dst_ip[16]; | 1667 | u8 dst_ip[16]; |
1668 | /* Must be last */ | ||
1669 | u8 real_sz[0]; | ||
1662 | }; | 1670 | }; |
1663 | 1671 | ||
1664 | struct ib_flow_spec_ipv6 { | 1672 | struct ib_flow_spec_ipv6 { |
@@ -1671,6 +1679,8 @@ struct ib_flow_spec_ipv6 { | |||
1671 | struct ib_flow_tcp_udp_filter { | 1679 | struct ib_flow_tcp_udp_filter { |
1672 | __be16 dst_port; | 1680 | __be16 dst_port; |
1673 | __be16 src_port; | 1681 | __be16 src_port; |
1682 | /* Must be last */ | ||
1683 | u8 real_sz[0]; | ||
1674 | }; | 1684 | }; |
1675 | 1685 | ||
1676 | struct ib_flow_spec_tcp_udp { | 1686 | struct ib_flow_spec_tcp_udp { |