[SCTP] Fix sctp_get{pl}addrs() API to work with 32-bit apps on 64-bit kernels.

The old socket options are marked with a _OLD suffix so that the
existing 32-bit apps on 32-bit kernels do not break.

Signed-off-by: Ivan Skytte J�rgensen <isj-sctp@i1.dk>
Signed-off-by: Sridhar Samudrala <sri@us.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by Ivan Skytte J�rgensen and committed by David S. Miller 5fe467ee edb4a353

+245 -34
+18 -9
include/net/sctp/user.h
··· 103 103 #define SCTP_SOCKOPT_BINDX_REM SCTP_SOCKOPT_BINDX_REM 104 104 SCTP_SOCKOPT_PEELOFF, /* peel off association. */ 105 105 #define SCTP_SOCKOPT_PEELOFF SCTP_SOCKOPT_PEELOFF 106 - SCTP_GET_PEER_ADDRS_NUM, /* Get number of peer addresss. */ 107 - #define SCTP_GET_PEER_ADDRS_NUM SCTP_GET_PEER_ADDRS_NUM 108 - SCTP_GET_PEER_ADDRS, /* Get all peer addresss. */ 109 - #define SCTP_GET_PEER_ADDRS SCTP_GET_PEER_ADDRS 110 - SCTP_GET_LOCAL_ADDRS_NUM, /* Get number of local addresss. */ 111 - #define SCTP_GET_LOCAL_ADDRS_NUM SCTP_GET_LOCAL_ADDRS_NUM 112 - SCTP_GET_LOCAL_ADDRS, /* Get all local addresss. */ 113 - #define SCTP_GET_LOCAL_ADDRS SCTP_GET_LOCAL_ADDRS 106 + SCTP_GET_PEER_ADDRS_NUM_OLD, /* Get number of peer addresss. */ 107 + #define SCTP_GET_PEER_ADDRS_NUM_OLD SCTP_GET_PEER_ADDRS_NUM_OLD 108 + SCTP_GET_PEER_ADDRS_OLD, /* Get all peer addresss. */ 109 + #define SCTP_GET_PEER_ADDRS_OLD SCTP_GET_PEER_ADDRS_OLD 110 + SCTP_GET_LOCAL_ADDRS_NUM_OLD, /* Get number of local addresss. */ 111 + #define SCTP_GET_LOCAL_ADDRS_NUM_OLD SCTP_GET_LOCAL_ADDRS_NUM_OLD 112 + SCTP_GET_LOCAL_ADDRS_OLD, /* Get all local addresss. */ 113 + #define SCTP_GET_LOCAL_ADDRS_OLD SCTP_GET_LOCAL_ADDRS_OLD 114 114 SCTP_SOCKOPT_CONNECTX, /* CONNECTX requests. */ 115 115 #define SCTP_SOCKOPT_CONNECTX SCTP_SOCKOPT_CONNECTX 116 + SCTP_GET_PEER_ADDRS, /* Get all peer addresss. */ 117 + #define SCTP_GET_PEER_ADDRS SCTP_GET_PEER_ADDRS 118 + SCTP_GET_LOCAL_ADDRS, /* Get all local addresss. */ 119 + #define SCTP_GET_LOCAL_ADDRS SCTP_GET_LOCAL_ADDRS 116 120 }; 117 121 118 122 /* ··· 563 559 * SCTP_GET_LOCAL_ADDRS socket options used internally to implement 564 560 * sctp_getpaddrs() and sctp_getladdrs() API. 565 561 */ 566 - struct sctp_getaddrs { 562 + struct sctp_getaddrs_old { 567 563 sctp_assoc_t assoc_id; 568 564 int addr_num; 569 565 struct sockaddr __user *addrs; 566 + }; 567 + struct sctp_getaddrs { 568 + sctp_assoc_t assoc_id; /*input*/ 569 + __u32 addr_num; /*output*/ 570 + __u8 addrs[0]; /*output, variable size*/ 570 571 }; 571 572 572 573 /* These are bit fields for msghdr->msg_flags. See section 5.1. */
+227 -25
net/sctp/socket.c
··· 3159 3159 return 0; 3160 3160 } 3161 3161 3162 - static int sctp_getsockopt_peer_addrs_num(struct sock *sk, int len, 3163 - char __user *optval, int __user *optlen) 3162 + static int sctp_getsockopt_peer_addrs_num_old(struct sock *sk, int len, 3163 + char __user *optval, 3164 + int __user *optlen) 3164 3165 { 3165 3166 sctp_assoc_t id; 3166 3167 struct sctp_association *asoc; ··· 3186 3185 return cnt; 3187 3186 } 3188 3187 3189 - static int sctp_getsockopt_peer_addrs(struct sock *sk, int len, 3190 - char __user *optval, int __user *optlen) 3188 + /* 3189 + * Old API for getting list of peer addresses. Does not work for 32-bit 3190 + * programs running on a 64-bit kernel 3191 + */ 3192 + static int sctp_getsockopt_peer_addrs_old(struct sock *sk, int len, 3193 + char __user *optval, 3194 + int __user *optlen) 3191 3195 { 3192 3196 struct sctp_association *asoc; 3193 3197 struct list_head *pos; 3194 3198 int cnt = 0; 3195 - struct sctp_getaddrs getaddrs; 3199 + struct sctp_getaddrs_old getaddrs; 3196 3200 struct sctp_transport *from; 3197 3201 void __user *to; 3198 3202 union sctp_addr temp; 3199 3203 struct sctp_sock *sp = sctp_sk(sk); 3200 3204 int addrlen; 3201 3205 3202 - if (len != sizeof(struct sctp_getaddrs)) 3206 + if (len != sizeof(struct sctp_getaddrs_old)) 3203 3207 return -EINVAL; 3204 3208 3205 - if (copy_from_user(&getaddrs, optval, sizeof(struct sctp_getaddrs))) 3209 + if (copy_from_user(&getaddrs, optval, sizeof(struct sctp_getaddrs_old))) 3206 3210 return -EFAULT; 3207 3211 3208 3212 if (getaddrs.addr_num <= 0) return -EINVAL; ··· 3231 3225 if (cnt >= getaddrs.addr_num) break; 3232 3226 } 3233 3227 getaddrs.addr_num = cnt; 3234 - if (copy_to_user(optval, &getaddrs, sizeof(struct sctp_getaddrs))) 3228 + if (copy_to_user(optval, &getaddrs, sizeof(struct sctp_getaddrs_old))) 3235 3229 return -EFAULT; 3236 3230 3237 3231 return 0; 3238 3232 } 3239 3233 3240 - static int sctp_getsockopt_local_addrs_num(struct sock *sk, int len, 3241 - char __user *optval, 3242 - int __user *optlen) 3234 + static int sctp_getsockopt_peer_addrs(struct sock *sk, int len, 3235 + char __user *optval, int __user *optlen) 3236 + { 3237 + struct sctp_association *asoc; 3238 + struct list_head *pos; 3239 + int cnt = 0; 3240 + struct sctp_getaddrs getaddrs; 3241 + struct sctp_transport *from; 3242 + void __user *to; 3243 + union sctp_addr temp; 3244 + struct sctp_sock *sp = sctp_sk(sk); 3245 + int addrlen; 3246 + size_t space_left; 3247 + int bytes_copied; 3248 + 3249 + if (len < sizeof(struct sctp_getaddrs)) 3250 + return -EINVAL; 3251 + 3252 + if (copy_from_user(&getaddrs, optval, sizeof(struct sctp_getaddrs))) 3253 + return -EFAULT; 3254 + 3255 + /* For UDP-style sockets, id specifies the association to query. */ 3256 + asoc = sctp_id2assoc(sk, getaddrs.assoc_id); 3257 + if (!asoc) 3258 + return -EINVAL; 3259 + 3260 + to = optval + offsetof(struct sctp_getaddrs,addrs); 3261 + space_left = len - sizeof(struct sctp_getaddrs) - 3262 + offsetof(struct sctp_getaddrs,addrs); 3263 + 3264 + list_for_each(pos, &asoc->peer.transport_addr_list) { 3265 + from = list_entry(pos, struct sctp_transport, transports); 3266 + memcpy(&temp, &from->ipaddr, sizeof(temp)); 3267 + sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp); 3268 + addrlen = sctp_get_af_specific(sk->sk_family)->sockaddr_len; 3269 + if(space_left < addrlen) 3270 + return -ENOMEM; 3271 + temp.v4.sin_port = htons(temp.v4.sin_port); 3272 + if (copy_to_user(to, &temp, addrlen)) 3273 + return -EFAULT; 3274 + to += addrlen; 3275 + cnt++; 3276 + space_left -= addrlen; 3277 + } 3278 + 3279 + if (put_user(cnt, &((struct sctp_getaddrs __user *)optval)->addr_num)) 3280 + return -EFAULT; 3281 + bytes_copied = ((char __user *)to) - optval; 3282 + if (put_user(bytes_copied, optlen)) 3283 + return -EFAULT; 3284 + 3285 + return 0; 3286 + } 3287 + 3288 + static int sctp_getsockopt_local_addrs_num_old(struct sock *sk, int len, 3289 + char __user *optval, 3290 + int __user *optlen) 3243 3291 { 3244 3292 sctp_assoc_t id; 3245 3293 struct sctp_bind_addr *bp; ··· 3366 3306 /* Helper function that copies local addresses to user and returns the number 3367 3307 * of addresses copied. 3368 3308 */ 3369 - static int sctp_copy_laddrs_to_user(struct sock *sk, __u16 port, int max_addrs, 3370 - void __user *to) 3309 + static int sctp_copy_laddrs_to_user_old(struct sock *sk, __u16 port, int max_addrs, 3310 + void __user *to) 3371 3311 { 3372 3312 struct list_head *pos; 3373 3313 struct sctp_sockaddr_entry *addr; ··· 3401 3341 return cnt; 3402 3342 } 3403 3343 3404 - static int sctp_getsockopt_local_addrs(struct sock *sk, int len, 3405 - char __user *optval, int __user *optlen) 3344 + static int sctp_copy_laddrs_to_user(struct sock *sk, __u16 port, 3345 + void * __user *to, size_t space_left) 3346 + { 3347 + struct list_head *pos; 3348 + struct sctp_sockaddr_entry *addr; 3349 + unsigned long flags; 3350 + union sctp_addr temp; 3351 + int cnt = 0; 3352 + int addrlen; 3353 + 3354 + sctp_spin_lock_irqsave(&sctp_local_addr_lock, flags); 3355 + list_for_each(pos, &sctp_local_addr_list) { 3356 + addr = list_entry(pos, struct sctp_sockaddr_entry, list); 3357 + if ((PF_INET == sk->sk_family) && 3358 + (AF_INET6 == addr->a.sa.sa_family)) 3359 + continue; 3360 + memcpy(&temp, &addr->a, sizeof(temp)); 3361 + sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk), 3362 + &temp); 3363 + addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len; 3364 + if(space_left<addrlen) 3365 + return -ENOMEM; 3366 + temp.v4.sin_port = htons(port); 3367 + if (copy_to_user(*to, &temp, addrlen)) { 3368 + sctp_spin_unlock_irqrestore(&sctp_local_addr_lock, 3369 + flags); 3370 + return -EFAULT; 3371 + } 3372 + *to += addrlen; 3373 + cnt ++; 3374 + space_left -= addrlen; 3375 + } 3376 + sctp_spin_unlock_irqrestore(&sctp_local_addr_lock, flags); 3377 + 3378 + return cnt; 3379 + } 3380 + 3381 + /* Old API for getting list of local addresses. Does not work for 32-bit 3382 + * programs running on a 64-bit kernel 3383 + */ 3384 + static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len, 3385 + char __user *optval, int __user *optlen) 3406 3386 { 3407 3387 struct sctp_bind_addr *bp; 3408 3388 struct sctp_association *asoc; 3409 3389 struct list_head *pos; 3410 3390 int cnt = 0; 3411 - struct sctp_getaddrs getaddrs; 3391 + struct sctp_getaddrs_old getaddrs; 3412 3392 struct sctp_sockaddr_entry *addr; 3413 3393 void __user *to; 3414 3394 union sctp_addr temp; ··· 3457 3357 rwlock_t *addr_lock; 3458 3358 int err = 0; 3459 3359 3460 - if (len != sizeof(struct sctp_getaddrs)) 3360 + if (len != sizeof(struct sctp_getaddrs_old)) 3461 3361 return -EINVAL; 3462 3362 3463 - if (copy_from_user(&getaddrs, optval, sizeof(struct sctp_getaddrs))) 3363 + if (copy_from_user(&getaddrs, optval, sizeof(struct sctp_getaddrs_old))) 3464 3364 return -EFAULT; 3465 3365 3466 3366 if (getaddrs.addr_num <= 0) return -EINVAL; ··· 3492 3392 addr = list_entry(bp->address_list.next, 3493 3393 struct sctp_sockaddr_entry, list); 3494 3394 if (sctp_is_any(&addr->a)) { 3495 - cnt = sctp_copy_laddrs_to_user(sk, bp->port, 3496 - getaddrs.addr_num, to); 3395 + cnt = sctp_copy_laddrs_to_user_old(sk, bp->port, 3396 + getaddrs.addr_num, 3397 + to); 3497 3398 if (cnt < 0) { 3498 3399 err = cnt; 3499 3400 goto unlock; ··· 3520 3419 3521 3420 copy_getaddrs: 3522 3421 getaddrs.addr_num = cnt; 3523 - if (copy_to_user(optval, &getaddrs, sizeof(struct sctp_getaddrs))) 3422 + if (copy_to_user(optval, &getaddrs, sizeof(struct sctp_getaddrs_old))) 3524 3423 err = -EFAULT; 3424 + 3425 + unlock: 3426 + sctp_read_unlock(addr_lock); 3427 + return err; 3428 + } 3429 + 3430 + static int sctp_getsockopt_local_addrs(struct sock *sk, int len, 3431 + char __user *optval, int __user *optlen) 3432 + { 3433 + struct sctp_bind_addr *bp; 3434 + struct sctp_association *asoc; 3435 + struct list_head *pos; 3436 + int cnt = 0; 3437 + struct sctp_getaddrs getaddrs; 3438 + struct sctp_sockaddr_entry *addr; 3439 + void __user *to; 3440 + union sctp_addr temp; 3441 + struct sctp_sock *sp = sctp_sk(sk); 3442 + int addrlen; 3443 + rwlock_t *addr_lock; 3444 + int err = 0; 3445 + size_t space_left; 3446 + int bytes_copied; 3447 + 3448 + if (len <= sizeof(struct sctp_getaddrs)) 3449 + return -EINVAL; 3450 + 3451 + if (copy_from_user(&getaddrs, optval, sizeof(struct sctp_getaddrs))) 3452 + return -EFAULT; 3453 + 3454 + /* 3455 + * For UDP-style sockets, id specifies the association to query. 3456 + * If the id field is set to the value '0' then the locally bound 3457 + * addresses are returned without regard to any particular 3458 + * association. 3459 + */ 3460 + if (0 == getaddrs.assoc_id) { 3461 + bp = &sctp_sk(sk)->ep->base.bind_addr; 3462 + addr_lock = &sctp_sk(sk)->ep->base.addr_lock; 3463 + } else { 3464 + asoc = sctp_id2assoc(sk, getaddrs.assoc_id); 3465 + if (!asoc) 3466 + return -EINVAL; 3467 + bp = &asoc->base.bind_addr; 3468 + addr_lock = &asoc->base.addr_lock; 3469 + } 3470 + 3471 + to = optval + offsetof(struct sctp_getaddrs,addrs); 3472 + space_left = len - sizeof(struct sctp_getaddrs) - 3473 + offsetof(struct sctp_getaddrs,addrs); 3474 + 3475 + sctp_read_lock(addr_lock); 3476 + 3477 + /* If the endpoint is bound to 0.0.0.0 or ::0, get the valid 3478 + * addresses from the global local address list. 3479 + */ 3480 + if (sctp_list_single_entry(&bp->address_list)) { 3481 + addr = list_entry(bp->address_list.next, 3482 + struct sctp_sockaddr_entry, list); 3483 + if (sctp_is_any(&addr->a)) { 3484 + cnt = sctp_copy_laddrs_to_user(sk, bp->port, 3485 + &to, space_left); 3486 + if (cnt < 0) { 3487 + err = cnt; 3488 + goto unlock; 3489 + } 3490 + goto copy_getaddrs; 3491 + } 3492 + } 3493 + 3494 + list_for_each(pos, &bp->address_list) { 3495 + addr = list_entry(pos, struct sctp_sockaddr_entry, list); 3496 + memcpy(&temp, &addr->a, sizeof(temp)); 3497 + sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp); 3498 + addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len; 3499 + if(space_left < addrlen) 3500 + return -ENOMEM; /*fixme: right error?*/ 3501 + temp.v4.sin_port = htons(temp.v4.sin_port); 3502 + if (copy_to_user(to, &temp, addrlen)) { 3503 + err = -EFAULT; 3504 + goto unlock; 3505 + } 3506 + to += addrlen; 3507 + cnt ++; 3508 + space_left -= addrlen; 3509 + } 3510 + 3511 + copy_getaddrs: 3512 + if (put_user(cnt, &((struct sctp_getaddrs __user *)optval)->addr_num)) 3513 + return -EFAULT; 3514 + bytes_copied = ((char __user *)to) - optval; 3515 + if (put_user(bytes_copied, optlen)) 3516 + return -EFAULT; 3525 3517 3526 3518 unlock: 3527 3519 sctp_read_unlock(addr_lock); ··· 4001 3807 case SCTP_INITMSG: 4002 3808 retval = sctp_getsockopt_initmsg(sk, len, optval, optlen); 4003 3809 break; 4004 - case SCTP_GET_PEER_ADDRS_NUM: 4005 - retval = sctp_getsockopt_peer_addrs_num(sk, len, optval, 3810 + case SCTP_GET_PEER_ADDRS_NUM_OLD: 3811 + retval = sctp_getsockopt_peer_addrs_num_old(sk, len, optval, 3812 + optlen); 3813 + break; 3814 + case SCTP_GET_LOCAL_ADDRS_NUM_OLD: 3815 + retval = sctp_getsockopt_local_addrs_num_old(sk, len, optval, 3816 + optlen); 3817 + break; 3818 + case SCTP_GET_PEER_ADDRS_OLD: 3819 + retval = sctp_getsockopt_peer_addrs_old(sk, len, optval, 4006 3820 optlen); 4007 3821 break; 4008 - case SCTP_GET_LOCAL_ADDRS_NUM: 4009 - retval = sctp_getsockopt_local_addrs_num(sk, len, optval, 3822 + case SCTP_GET_LOCAL_ADDRS_OLD: 3823 + retval = sctp_getsockopt_local_addrs_old(sk, len, optval, 4010 3824 optlen); 4011 3825 break; 4012 3826 case SCTP_GET_PEER_ADDRS: