diff options
| -rw-r--r-- | net/sctp/socket.c | 59 |
1 files changed, 11 insertions, 48 deletions
diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 3204a9b29407..c2cccc9902d6 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c | |||
| @@ -970,13 +970,6 @@ int sctp_asconf_mgmt(struct sctp_sock *sp, struct sctp_sockaddr_entry *addrw) | |||
| 970 | * This is used for tunneling the sctp_bindx() request through sctp_setsockopt() | 970 | * This is used for tunneling the sctp_bindx() request through sctp_setsockopt() |
| 971 | * from userspace. | 971 | * from userspace. |
| 972 | * | 972 | * |
| 973 | * We don't use copy_from_user() for optimization: we first do the | ||
| 974 | * sanity checks (buffer size -fast- and access check-healthy | ||
| 975 | * pointer); if all of those succeed, then we can alloc the memory | ||
| 976 | * (expensive operation) needed to copy the data to kernel. Then we do | ||
| 977 | * the copying without checking the user space area | ||
| 978 | * (__copy_from_user()). | ||
| 979 | * | ||
| 980 | * On exit there is no need to do sockfd_put(), sys_setsockopt() does | 973 | * On exit there is no need to do sockfd_put(), sys_setsockopt() does |
| 981 | * it. | 974 | * it. |
| 982 | * | 975 | * |
| @@ -1006,25 +999,15 @@ static int sctp_setsockopt_bindx(struct sock *sk, | |||
| 1006 | if (unlikely(addrs_size <= 0)) | 999 | if (unlikely(addrs_size <= 0)) |
| 1007 | return -EINVAL; | 1000 | return -EINVAL; |
| 1008 | 1001 | ||
| 1009 | /* Check the user passed a healthy pointer. */ | 1002 | kaddrs = vmemdup_user(addrs, addrs_size); |
| 1010 | if (unlikely(!access_ok(VERIFY_READ, addrs, addrs_size))) | 1003 | if (unlikely(IS_ERR(kaddrs))) |
| 1011 | return -EFAULT; | 1004 | return PTR_ERR(kaddrs); |
| 1012 | |||
| 1013 | /* Alloc space for the address array in kernel memory. */ | ||
| 1014 | kaddrs = kmalloc(addrs_size, GFP_USER | __GFP_NOWARN); | ||
| 1015 | if (unlikely(!kaddrs)) | ||
| 1016 | return -ENOMEM; | ||
| 1017 | |||
| 1018 | if (__copy_from_user(kaddrs, addrs, addrs_size)) { | ||
| 1019 | kfree(kaddrs); | ||
| 1020 | return -EFAULT; | ||
| 1021 | } | ||
| 1022 | 1005 | ||
| 1023 | /* Walk through the addrs buffer and count the number of addresses. */ | 1006 | /* Walk through the addrs buffer and count the number of addresses. */ |
| 1024 | addr_buf = kaddrs; | 1007 | addr_buf = kaddrs; |
| 1025 | while (walk_size < addrs_size) { | 1008 | while (walk_size < addrs_size) { |
| 1026 | if (walk_size + sizeof(sa_family_t) > addrs_size) { | 1009 | if (walk_size + sizeof(sa_family_t) > addrs_size) { |
| 1027 | kfree(kaddrs); | 1010 | kvfree(kaddrs); |
| 1028 | return -EINVAL; | 1011 | return -EINVAL; |
| 1029 | } | 1012 | } |
| 1030 | 1013 | ||
| @@ -1035,7 +1018,7 @@ static int sctp_setsockopt_bindx(struct sock *sk, | |||
| 1035 | * causes the address buffer to overflow return EINVAL. | 1018 | * causes the address buffer to overflow return EINVAL. |
| 1036 | */ | 1019 | */ |
| 1037 | if (!af || (walk_size + af->sockaddr_len) > addrs_size) { | 1020 | if (!af || (walk_size + af->sockaddr_len) > addrs_size) { |
| 1038 | kfree(kaddrs); | 1021 | kvfree(kaddrs); |
| 1039 | return -EINVAL; | 1022 | return -EINVAL; |
| 1040 | } | 1023 | } |
| 1041 | addrcnt++; | 1024 | addrcnt++; |
| @@ -1065,7 +1048,7 @@ static int sctp_setsockopt_bindx(struct sock *sk, | |||
| 1065 | } | 1048 | } |
| 1066 | 1049 | ||
| 1067 | out: | 1050 | out: |
| 1068 | kfree(kaddrs); | 1051 | kvfree(kaddrs); |
| 1069 | 1052 | ||
| 1070 | return err; | 1053 | return err; |
| 1071 | } | 1054 | } |
| @@ -1323,13 +1306,6 @@ out_free: | |||
| 1323 | * land and invoking either sctp_connectx(). This is used for tunneling | 1306 | * land and invoking either sctp_connectx(). This is used for tunneling |
| 1324 | * the sctp_connectx() request through sctp_setsockopt() from userspace. | 1307 | * the sctp_connectx() request through sctp_setsockopt() from userspace. |
| 1325 | * | 1308 | * |
| 1326 | * We don't use copy_from_user() for optimization: we first do the | ||
| 1327 | * sanity checks (buffer size -fast- and access check-healthy | ||
| 1328 | * pointer); if all of those succeed, then we can alloc the memory | ||
| 1329 | * (expensive operation) needed to copy the data to kernel. Then we do | ||
| 1330 | * the copying without checking the user space area | ||
| 1331 | * (__copy_from_user()). | ||
| 1332 | * | ||
| 1333 | * On exit there is no need to do sockfd_put(), sys_setsockopt() does | 1309 | * On exit there is no need to do sockfd_put(), sys_setsockopt() does |
| 1334 | * it. | 1310 | * it. |
| 1335 | * | 1311 | * |
| @@ -1345,7 +1321,6 @@ static int __sctp_setsockopt_connectx(struct sock *sk, | |||
| 1345 | sctp_assoc_t *assoc_id) | 1321 | sctp_assoc_t *assoc_id) |
| 1346 | { | 1322 | { |
| 1347 | struct sockaddr *kaddrs; | 1323 | struct sockaddr *kaddrs; |
| 1348 | gfp_t gfp = GFP_KERNEL; | ||
| 1349 | int err = 0; | 1324 | int err = 0; |
| 1350 | 1325 | ||
| 1351 | pr_debug("%s: sk:%p addrs:%p addrs_size:%d\n", | 1326 | pr_debug("%s: sk:%p addrs:%p addrs_size:%d\n", |
| @@ -1354,24 +1329,12 @@ static int __sctp_setsockopt_connectx(struct sock *sk, | |||
| 1354 | if (unlikely(addrs_size <= 0)) | 1329 | if (unlikely(addrs_size <= 0)) |
| 1355 | return -EINVAL; | 1330 | return -EINVAL; |
| 1356 | 1331 | ||
| 1357 | /* Check the user passed a healthy pointer. */ | 1332 | kaddrs = vmemdup_user(addrs, addrs_size); |
| 1358 | if (unlikely(!access_ok(VERIFY_READ, addrs, addrs_size))) | 1333 | if (unlikely(IS_ERR(kaddrs))) |
| 1359 | return -EFAULT; | 1334 | return PTR_ERR(kaddrs); |
| 1360 | |||
| 1361 | /* Alloc space for the address array in kernel memory. */ | ||
| 1362 | if (sk->sk_socket->file) | ||
| 1363 | gfp = GFP_USER | __GFP_NOWARN; | ||
| 1364 | kaddrs = kmalloc(addrs_size, gfp); | ||
| 1365 | if (unlikely(!kaddrs)) | ||
| 1366 | return -ENOMEM; | ||
| 1367 | |||
| 1368 | if (__copy_from_user(kaddrs, addrs, addrs_size)) { | ||
| 1369 | err = -EFAULT; | ||
| 1370 | } else { | ||
| 1371 | err = __sctp_connect(sk, kaddrs, addrs_size, assoc_id); | ||
| 1372 | } | ||
| 1373 | 1335 | ||
| 1374 | kfree(kaddrs); | 1336 | err = __sctp_connect(sk, kaddrs, addrs_size, assoc_id); |
| 1337 | kvfree(kaddrs); | ||
| 1375 | 1338 | ||
| 1376 | return err; | 1339 | return err; |
| 1377 | } | 1340 | } |
