46
46
47
47
#include <net/tcp.h>
48
48
#include <net/ipv6.h>
49
+ #include <net/ip_fib.h>
50
+ #include <net/ip6_route.h>
49
51
50
52
#include <rdma/rdma_cm.h>
51
53
#include <rdma/rdma_cm_ib.h>
@@ -1081,16 +1083,98 @@ static int cma_save_req_info(const struct ib_cm_event *ib_event,
1081
1083
return 0 ;
1082
1084
}
1083
1085
1086
+ static bool validate_ipv4_net_dev (struct net_device * net_dev ,
1087
+ const struct sockaddr_in * dst_addr ,
1088
+ const struct sockaddr_in * src_addr )
1089
+ {
1090
+ __be32 daddr = dst_addr -> sin_addr .s_addr ,
1091
+ saddr = src_addr -> sin_addr .s_addr ;
1092
+ struct fib_result res ;
1093
+ struct flowi4 fl4 ;
1094
+ int err ;
1095
+ bool ret ;
1096
+
1097
+ if (ipv4_is_multicast (saddr ) || ipv4_is_lbcast (saddr ) ||
1098
+ ipv4_is_lbcast (daddr ) || ipv4_is_zeronet (saddr ) ||
1099
+ ipv4_is_zeronet (daddr ) || ipv4_is_loopback (daddr ) ||
1100
+ ipv4_is_loopback (saddr ))
1101
+ return false;
1102
+
1103
+ memset (& fl4 , 0 , sizeof (fl4 ));
1104
+ fl4 .flowi4_iif = net_dev -> ifindex ;
1105
+ fl4 .daddr = daddr ;
1106
+ fl4 .saddr = saddr ;
1107
+
1108
+ rcu_read_lock ();
1109
+ err = fib_lookup (dev_net (net_dev ), & fl4 , & res , 0 );
1110
+ if (err )
1111
+ return false;
1112
+
1113
+ ret = FIB_RES_DEV (res ) == net_dev ;
1114
+ rcu_read_unlock ();
1115
+
1116
+ return ret ;
1117
+ }
1118
+
1119
+ static bool validate_ipv6_net_dev (struct net_device * net_dev ,
1120
+ const struct sockaddr_in6 * dst_addr ,
1121
+ const struct sockaddr_in6 * src_addr )
1122
+ {
1123
+ #if IS_ENABLED (CONFIG_IPV6 )
1124
+ const int strict = ipv6_addr_type (& dst_addr -> sin6_addr ) &
1125
+ IPV6_ADDR_LINKLOCAL ;
1126
+ struct rt6_info * rt = rt6_lookup (dev_net (net_dev ), & dst_addr -> sin6_addr ,
1127
+ & src_addr -> sin6_addr , net_dev -> ifindex ,
1128
+ strict );
1129
+ bool ret ;
1130
+
1131
+ if (!rt )
1132
+ return false;
1133
+
1134
+ ret = rt -> rt6i_idev -> dev == net_dev ;
1135
+ ip6_rt_put (rt );
1136
+
1137
+ return ret ;
1138
+ #else
1139
+ return false;
1140
+ #endif
1141
+ }
1142
+
1143
+ static bool validate_net_dev (struct net_device * net_dev ,
1144
+ const struct sockaddr * daddr ,
1145
+ const struct sockaddr * saddr )
1146
+ {
1147
+ const struct sockaddr_in * daddr4 = (const struct sockaddr_in * )daddr ;
1148
+ const struct sockaddr_in * saddr4 = (const struct sockaddr_in * )saddr ;
1149
+ const struct sockaddr_in6 * daddr6 = (const struct sockaddr_in6 * )daddr ;
1150
+ const struct sockaddr_in6 * saddr6 = (const struct sockaddr_in6 * )saddr ;
1151
+
1152
+ switch (daddr -> sa_family ) {
1153
+ case AF_INET :
1154
+ return saddr -> sa_family == AF_INET &&
1155
+ validate_ipv4_net_dev (net_dev , daddr4 , saddr4 );
1156
+
1157
+ case AF_INET6 :
1158
+ return saddr -> sa_family == AF_INET6 &&
1159
+ validate_ipv6_net_dev (net_dev , daddr6 , saddr6 );
1160
+
1161
+ default :
1162
+ return false;
1163
+ }
1164
+ }
1165
+
1084
1166
static struct net_device * cma_get_net_dev (struct ib_cm_event * ib_event ,
1085
1167
const struct cma_req_info * req )
1086
1168
{
1087
- struct sockaddr_storage listen_addr_storage ;
1088
- struct sockaddr * listen_addr = (struct sockaddr * )& listen_addr_storage ;
1169
+ struct sockaddr_storage listen_addr_storage , src_addr_storage ;
1170
+ struct sockaddr * listen_addr = (struct sockaddr * )& listen_addr_storage ,
1171
+ * src_addr = (struct sockaddr * )& src_addr_storage ;
1089
1172
struct net_device * net_dev ;
1090
1173
const union ib_gid * gid = req -> has_gid ? & req -> local_gid : NULL ;
1091
1174
int err ;
1092
1175
1093
- err = cma_save_ip_info (listen_addr , NULL , ib_event , req -> service_id );
1176
+ err = cma_save_ip_info (listen_addr , src_addr , ib_event ,
1177
+ req -> service_id );
1094
1178
if (err )
1095
1179
return ERR_PTR (err );
1096
1180
@@ -1099,6 +1183,11 @@ static struct net_device *cma_get_net_dev(struct ib_cm_event *ib_event,
1099
1183
if (!net_dev )
1100
1184
return ERR_PTR (- ENODEV );
1101
1185
1186
+ if (!validate_net_dev (net_dev , listen_addr , src_addr )) {
1187
+ dev_put (net_dev );
1188
+ return ERR_PTR (- EHOSTUNREACH );
1189
+ }
1190
+
1102
1191
return net_dev ;
1103
1192
}
1104
1193
0 commit comments