aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/infiniband/core/uverbs_cmd.c98
-rw-r--r--include/rdma/ib_verbs.h10
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
3081static 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
3087static 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
3081static int kern_spec_to_ib_spec(struct ib_uverbs_flow_spec *kern_spec, 3105static 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
1628struct ib_flow_spec_eth { 1630struct ib_flow_spec_eth {
@@ -1635,6 +1637,8 @@ struct ib_flow_spec_eth {
1635struct ib_flow_ib_filter { 1637struct 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
1640struct ib_flow_spec_ib { 1644struct ib_flow_spec_ib {
@@ -1647,6 +1651,8 @@ struct ib_flow_spec_ib {
1647struct ib_flow_ipv4_filter { 1651struct 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
1652struct ib_flow_spec_ipv4 { 1658struct ib_flow_spec_ipv4 {
@@ -1659,6 +1665,8 @@ struct ib_flow_spec_ipv4 {
1659struct ib_flow_ipv6_filter { 1665struct 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
1664struct ib_flow_spec_ipv6 { 1672struct ib_flow_spec_ipv6 {
@@ -1671,6 +1679,8 @@ struct ib_flow_spec_ipv6 {
1671struct ib_flow_tcp_udp_filter { 1679struct 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
1676struct ib_flow_spec_tcp_udp { 1686struct ib_flow_spec_tcp_udp {