aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/sctp/socket.c96
1 files changed, 60 insertions, 36 deletions
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 11938fb20395..2fc0a92caa78 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -3987,7 +3987,7 @@ static int sctp_getsockopt_peer_addrs(struct sock *sk, int len,
3987 memcpy(&temp, &from->ipaddr, sizeof(temp)); 3987 memcpy(&temp, &from->ipaddr, sizeof(temp));
3988 sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp); 3988 sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp);
3989 addrlen = sctp_get_af_specific(sk->sk_family)->sockaddr_len; 3989 addrlen = sctp_get_af_specific(sk->sk_family)->sockaddr_len;
3990 if(space_left < addrlen) 3990 if (space_left < addrlen)
3991 return -ENOMEM; 3991 return -ENOMEM;
3992 if (copy_to_user(to, &temp, addrlen)) 3992 if (copy_to_user(to, &temp, addrlen))
3993 return -EFAULT; 3993 return -EFAULT;
@@ -4076,8 +4076,9 @@ done:
4076/* Helper function that copies local addresses to user and returns the number 4076/* Helper function that copies local addresses to user and returns the number
4077 * of addresses copied. 4077 * of addresses copied.
4078 */ 4078 */
4079static int sctp_copy_laddrs_to_user_old(struct sock *sk, __u16 port, int max_addrs, 4079static int sctp_copy_laddrs_old(struct sock *sk, __u16 port,
4080 void __user *to) 4080 int max_addrs, void *to,
4081 int *bytes_copied)
4081{ 4082{
4082 struct list_head *pos, *next; 4083 struct list_head *pos, *next;
4083 struct sctp_sockaddr_entry *addr; 4084 struct sctp_sockaddr_entry *addr;
@@ -4094,10 +4095,10 @@ static int sctp_copy_laddrs_to_user_old(struct sock *sk, __u16 port, int max_add
4094 sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk), 4095 sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk),
4095 &temp); 4096 &temp);
4096 addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len; 4097 addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len;
4097 if (copy_to_user(to, &temp, addrlen)) 4098 memcpy(to, &temp, addrlen);
4098 return -EFAULT;
4099 4099
4100 to += addrlen; 4100 to += addrlen;
4101 *bytes_copied += addrlen;
4101 cnt ++; 4102 cnt ++;
4102 if (cnt >= max_addrs) break; 4103 if (cnt >= max_addrs) break;
4103 } 4104 }
@@ -4105,8 +4106,8 @@ static int sctp_copy_laddrs_to_user_old(struct sock *sk, __u16 port, int max_add
4105 return cnt; 4106 return cnt;
4106} 4107}
4107 4108
4108static int sctp_copy_laddrs_to_user(struct sock *sk, __u16 port, 4109static int sctp_copy_laddrs(struct sock *sk, __u16 port, void *to,
4109 void __user **to, size_t space_left) 4110 size_t space_left, int *bytes_copied)
4110{ 4111{
4111 struct list_head *pos, *next; 4112 struct list_head *pos, *next;
4112 struct sctp_sockaddr_entry *addr; 4113 struct sctp_sockaddr_entry *addr;
@@ -4123,14 +4124,14 @@ static int sctp_copy_laddrs_to_user(struct sock *sk, __u16 port,
4123 sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk), 4124 sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk),
4124 &temp); 4125 &temp);
4125 addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len; 4126 addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len;
4126 if(space_left<addrlen) 4127 if (space_left < addrlen)
4127 return -ENOMEM; 4128 return -ENOMEM;
4128 if (copy_to_user(*to, &temp, addrlen)) 4129 memcpy(to, &temp, addrlen);
4129 return -EFAULT;
4130 4130
4131 *to += addrlen; 4131 to += addrlen;
4132 cnt ++; 4132 cnt ++;
4133 space_left -= addrlen; 4133 space_left -= addrlen;
4134 bytes_copied += addrlen;
4134 } 4135 }
4135 4136
4136 return cnt; 4137 return cnt;
@@ -4154,6 +4155,8 @@ static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len,
4154 int addrlen; 4155 int addrlen;
4155 rwlock_t *addr_lock; 4156 rwlock_t *addr_lock;
4156 int err = 0; 4157 int err = 0;
4158 void *addrs;
4159 int bytes_copied = 0;
4157 4160
4158 if (len != sizeof(struct sctp_getaddrs_old)) 4161 if (len != sizeof(struct sctp_getaddrs_old))
4159 return -EINVAL; 4162 return -EINVAL;
@@ -4181,6 +4184,15 @@ static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len,
4181 4184
4182 to = getaddrs.addrs; 4185 to = getaddrs.addrs;
4183 4186
4187 /* Allocate space for a local instance of packed array to hold all
4188 * the data. We store addresses here first and then put write them
4189 * to the user in one shot.
4190 */
4191 addrs = kmalloc(sizeof(union sctp_addr) * getaddrs.addr_num,
4192 GFP_KERNEL);
4193 if (!addrs)
4194 return -ENOMEM;
4195
4184 sctp_read_lock(addr_lock); 4196 sctp_read_lock(addr_lock);
4185 4197
4186 /* If the endpoint is bound to 0.0.0.0 or ::0, get the valid 4198 /* If the endpoint is bound to 0.0.0.0 or ::0, get the valid
@@ -4190,13 +4202,9 @@ static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len,
4190 addr = list_entry(bp->address_list.next, 4202 addr = list_entry(bp->address_list.next,
4191 struct sctp_sockaddr_entry, list); 4203 struct sctp_sockaddr_entry, list);
4192 if (sctp_is_any(&addr->a)) { 4204 if (sctp_is_any(&addr->a)) {
4193 cnt = sctp_copy_laddrs_to_user_old(sk, bp->port, 4205 cnt = sctp_copy_laddrs_old(sk, bp->port,
4194 getaddrs.addr_num, 4206 getaddrs.addr_num,
4195 to); 4207 addrs, &bytes_copied);
4196 if (cnt < 0) {
4197 err = cnt;
4198 goto unlock;
4199 }
4200 goto copy_getaddrs; 4208 goto copy_getaddrs;
4201 } 4209 }
4202 } 4210 }
@@ -4206,22 +4214,29 @@ static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len,
4206 memcpy(&temp, &addr->a, sizeof(temp)); 4214 memcpy(&temp, &addr->a, sizeof(temp));
4207 sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp); 4215 sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp);
4208 addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len; 4216 addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len;
4209 if (copy_to_user(to, &temp, addrlen)) { 4217 memcpy(addrs, &temp, addrlen);
4210 err = -EFAULT;
4211 goto unlock;
4212 }
4213 to += addrlen; 4218 to += addrlen;
4219 bytes_copied += addrlen;
4214 cnt ++; 4220 cnt ++;
4215 if (cnt >= getaddrs.addr_num) break; 4221 if (cnt >= getaddrs.addr_num) break;
4216 } 4222 }
4217 4223
4218copy_getaddrs: 4224copy_getaddrs:
4225 sctp_read_unlock(addr_lock);
4226
4227 /* copy the entire address list into the user provided space */
4228 if (copy_to_user(to, addrs, bytes_copied)) {
4229 err = -EFAULT;
4230 goto error;
4231 }
4232
4233 /* copy the leading structure back to user */
4219 getaddrs.addr_num = cnt; 4234 getaddrs.addr_num = cnt;
4220 if (copy_to_user(optval, &getaddrs, sizeof(struct sctp_getaddrs_old))) 4235 if (copy_to_user(optval, &getaddrs, sizeof(struct sctp_getaddrs_old)))
4221 err = -EFAULT; 4236 err = -EFAULT;
4222 4237
4223unlock: 4238error:
4224 sctp_read_unlock(addr_lock); 4239 kfree(addrs);
4225 return err; 4240 return err;
4226} 4241}
4227 4242
@@ -4241,7 +4256,8 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
4241 rwlock_t *addr_lock; 4256 rwlock_t *addr_lock;
4242 int err = 0; 4257 int err = 0;
4243 size_t space_left; 4258 size_t space_left;
4244 int bytes_copied; 4259 int bytes_copied = 0;
4260 void *addrs;
4245 4261
4246 if (len <= sizeof(struct sctp_getaddrs)) 4262 if (len <= sizeof(struct sctp_getaddrs))
4247 return -EINVAL; 4263 return -EINVAL;
@@ -4269,6 +4285,9 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
4269 to = optval + offsetof(struct sctp_getaddrs,addrs); 4285 to = optval + offsetof(struct sctp_getaddrs,addrs);
4270 space_left = len - sizeof(struct sctp_getaddrs) - 4286 space_left = len - sizeof(struct sctp_getaddrs) -
4271 offsetof(struct sctp_getaddrs,addrs); 4287 offsetof(struct sctp_getaddrs,addrs);
4288 addrs = kmalloc(space_left, GFP_KERNEL);
4289 if (!addrs)
4290 return -ENOMEM;
4272 4291
4273 sctp_read_lock(addr_lock); 4292 sctp_read_lock(addr_lock);
4274 4293
@@ -4279,11 +4298,11 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
4279 addr = list_entry(bp->address_list.next, 4298 addr = list_entry(bp->address_list.next,
4280 struct sctp_sockaddr_entry, list); 4299 struct sctp_sockaddr_entry, list);
4281 if (sctp_is_any(&addr->a)) { 4300 if (sctp_is_any(&addr->a)) {
4282 cnt = sctp_copy_laddrs_to_user(sk, bp->port, 4301 cnt = sctp_copy_laddrs(sk, bp->port, addrs,
4283 &to, space_left); 4302 space_left, &bytes_copied);
4284 if (cnt < 0) { 4303 if (cnt < 0) {
4285 err = cnt; 4304 err = cnt;
4286 goto unlock; 4305 goto error;
4287 } 4306 }
4288 goto copy_getaddrs; 4307 goto copy_getaddrs;
4289 } 4308 }
@@ -4294,26 +4313,31 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
4294 memcpy(&temp, &addr->a, sizeof(temp)); 4313 memcpy(&temp, &addr->a, sizeof(temp));
4295 sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp); 4314 sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp);
4296 addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len; 4315 addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len;
4297 if(space_left < addrlen) 4316 if (space_left < addrlen) {
4298 return -ENOMEM; /*fixme: right error?*/ 4317 err = -ENOMEM; /*fixme: right error?*/
4299 if (copy_to_user(to, &temp, addrlen)) { 4318 goto error;
4300 err = -EFAULT;
4301 goto unlock;
4302 } 4319 }
4320 memcpy(addrs, &temp, addrlen);
4303 to += addrlen; 4321 to += addrlen;
4322 bytes_copied += addrlen;
4304 cnt ++; 4323 cnt ++;
4305 space_left -= addrlen; 4324 space_left -= addrlen;
4306 } 4325 }
4307 4326
4308copy_getaddrs: 4327copy_getaddrs:
4328 sctp_read_unlock(addr_lock);
4329
4330 if (copy_to_user(to, addrs, bytes_copied)) {
4331 err = -EFAULT;
4332 goto error;
4333 }
4309 if (put_user(cnt, &((struct sctp_getaddrs __user *)optval)->addr_num)) 4334 if (put_user(cnt, &((struct sctp_getaddrs __user *)optval)->addr_num))
4310 return -EFAULT; 4335 return -EFAULT;
4311 bytes_copied = ((char __user *)to) - optval;
4312 if (put_user(bytes_copied, optlen)) 4336 if (put_user(bytes_copied, optlen))
4313 return -EFAULT; 4337 return -EFAULT;
4314 4338
4315unlock: 4339error:
4316 sctp_read_unlock(addr_lock); 4340 kfree(addrs);
4317 return err; 4341 return err;
4318} 4342}
4319 4343