aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrey Ignatov <rdna@fb.com>2018-03-30 18:08:04 -0400
committerDaniel Borkmann <daniel@iogearbox.net>2018-03-30 20:15:43 -0400
commit3679d585bbc07a1ac4448d5b478b492cad3587ce (patch)
tree15cfea104f4ee4dcb55005a2ca101631eefa3f2f
parente50b0a6f089308bec6b2d0198abed231dee4d277 (diff)
net: Introduce __inet_bind() and __inet6_bind
Refactor `bind()` code to make it ready to be called from BPF helper function `bpf_bind()` (will be added soon). Implementation of `inet_bind()` and `inet6_bind()` is separated into `__inet_bind()` and `__inet6_bind()` correspondingly. These function can be used from both `sk_prot->bind` and `bpf_bind()` contexts. New functions have two additional arguments. `force_bind_address_no_port` forces binding to IP only w/o checking `inet_sock.bind_address_no_port` field. It'll allow to bind local end of a connection to desired IP in `bpf_bind()` w/o changing `bind_address_no_port` field of a socket. It's useful since `bpf_bind()` can return an error and we'd need to restore original value of `bind_address_no_port` in that case if we changed this before calling to the helper. `with_lock` specifies whether to lock socket when working with `struct sk` or not. The argument is set to `true` for `sk_prot->bind`, i.e. old behavior is preserved. But it will be set to `false` for `bpf_bind()` use-case. The reason is all call-sites, where `bpf_bind()` will be called, already hold that socket lock. Signed-off-by: Andrey Ignatov <rdna@fb.com> Acked-by: Alexei Starovoitov <ast@kernel.org> Signed-off-by: Alexei Starovoitov <ast@kernel.org> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
-rw-r--r--include/net/inet_common.h2
-rw-r--r--include/net/ipv6.h2
-rw-r--r--net/ipv4/af_inet.c39
-rw-r--r--net/ipv6/af_inet6.c37
4 files changed, 52 insertions, 28 deletions
diff --git a/include/net/inet_common.h b/include/net/inet_common.h
index 500f81375200..384b90c62c0b 100644
--- a/include/net/inet_common.h
+++ b/include/net/inet_common.h
@@ -32,6 +32,8 @@ int inet_shutdown(struct socket *sock, int how);
32int inet_listen(struct socket *sock, int backlog); 32int inet_listen(struct socket *sock, int backlog);
33void inet_sock_destruct(struct sock *sk); 33void inet_sock_destruct(struct sock *sk);
34int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len); 34int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len);
35int __inet_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len,
36 bool force_bind_address_no_port, bool with_lock);
35int inet_getname(struct socket *sock, struct sockaddr *uaddr, 37int inet_getname(struct socket *sock, struct sockaddr *uaddr,
36 int peer); 38 int peer);
37int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg); 39int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg);
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index 50a6f0ddb878..2e5fedc56e59 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -1066,6 +1066,8 @@ void ipv6_local_error(struct sock *sk, int err, struct flowi6 *fl6, u32 info);
1066void ipv6_local_rxpmtu(struct sock *sk, struct flowi6 *fl6, u32 mtu); 1066void ipv6_local_rxpmtu(struct sock *sk, struct flowi6 *fl6, u32 mtu);
1067 1067
1068int inet6_release(struct socket *sock); 1068int inet6_release(struct socket *sock);
1069int __inet6_bind(struct sock *sock, struct sockaddr *uaddr, int addr_len,
1070 bool force_bind_address_no_port, bool with_lock);
1069int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len); 1071int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len);
1070int inet6_getname(struct socket *sock, struct sockaddr *uaddr, 1072int inet6_getname(struct socket *sock, struct sockaddr *uaddr,
1071 int peer); 1073 int peer);
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 2dec266507dc..e203a39d6988 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -432,30 +432,37 @@ EXPORT_SYMBOL(inet_release);
432 432
433int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) 433int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
434{ 434{
435 struct sockaddr_in *addr = (struct sockaddr_in *)uaddr;
436 struct sock *sk = sock->sk; 435 struct sock *sk = sock->sk;
437 struct inet_sock *inet = inet_sk(sk);
438 struct net *net = sock_net(sk);
439 unsigned short snum;
440 int chk_addr_ret;
441 u32 tb_id = RT_TABLE_LOCAL;
442 int err; 436 int err;
443 437
444 /* If the socket has its own bind function then use it. (RAW) */ 438 /* If the socket has its own bind function then use it. (RAW) */
445 if (sk->sk_prot->bind) { 439 if (sk->sk_prot->bind) {
446 err = sk->sk_prot->bind(sk, uaddr, addr_len); 440 return sk->sk_prot->bind(sk, uaddr, addr_len);
447 goto out;
448 } 441 }
449 err = -EINVAL;
450 if (addr_len < sizeof(struct sockaddr_in)) 442 if (addr_len < sizeof(struct sockaddr_in))
451 goto out; 443 return -EINVAL;
452 444
453 /* BPF prog is run before any checks are done so that if the prog 445 /* BPF prog is run before any checks are done so that if the prog
454 * changes context in a wrong way it will be caught. 446 * changes context in a wrong way it will be caught.
455 */ 447 */
456 err = BPF_CGROUP_RUN_PROG_INET4_BIND(sk, uaddr); 448 err = BPF_CGROUP_RUN_PROG_INET4_BIND(sk, uaddr);
457 if (err) 449 if (err)
458 goto out; 450 return err;
451
452 return __inet_bind(sk, uaddr, addr_len, false, true);
453}
454EXPORT_SYMBOL(inet_bind);
455
456int __inet_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len,
457 bool force_bind_address_no_port, bool with_lock)
458{
459 struct sockaddr_in *addr = (struct sockaddr_in *)uaddr;
460 struct inet_sock *inet = inet_sk(sk);
461 struct net *net = sock_net(sk);
462 unsigned short snum;
463 int chk_addr_ret;
464 u32 tb_id = RT_TABLE_LOCAL;
465 int err;
459 466
460 if (addr->sin_family != AF_INET) { 467 if (addr->sin_family != AF_INET) {
461 /* Compatibility games : accept AF_UNSPEC (mapped to AF_INET) 468 /* Compatibility games : accept AF_UNSPEC (mapped to AF_INET)
@@ -499,7 +506,8 @@ int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
499 * would be illegal to use them (multicast/broadcast) in 506 * would be illegal to use them (multicast/broadcast) in
500 * which case the sending device address is used. 507 * which case the sending device address is used.
501 */ 508 */
502 lock_sock(sk); 509 if (with_lock)
510 lock_sock(sk);
503 511
504 /* Check these errors (active socket, double bind). */ 512 /* Check these errors (active socket, double bind). */
505 err = -EINVAL; 513 err = -EINVAL;
@@ -511,7 +519,8 @@ int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
511 inet->inet_saddr = 0; /* Use device */ 519 inet->inet_saddr = 0; /* Use device */
512 520
513 /* Make sure we are allowed to bind here. */ 521 /* Make sure we are allowed to bind here. */
514 if ((snum || !inet->bind_address_no_port) && 522 if ((snum || !(inet->bind_address_no_port ||
523 force_bind_address_no_port)) &&
515 sk->sk_prot->get_port(sk, snum)) { 524 sk->sk_prot->get_port(sk, snum)) {
516 inet->inet_saddr = inet->inet_rcv_saddr = 0; 525 inet->inet_saddr = inet->inet_rcv_saddr = 0;
517 err = -EADDRINUSE; 526 err = -EADDRINUSE;
@@ -528,11 +537,11 @@ int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
528 sk_dst_reset(sk); 537 sk_dst_reset(sk);
529 err = 0; 538 err = 0;
530out_release_sock: 539out_release_sock:
531 release_sock(sk); 540 if (with_lock)
541 release_sock(sk);
532out: 542out:
533 return err; 543 return err;
534} 544}
535EXPORT_SYMBOL(inet_bind);
536 545
537int inet_dgram_connect(struct socket *sock, struct sockaddr *uaddr, 546int inet_dgram_connect(struct socket *sock, struct sockaddr *uaddr,
538 int addr_len, int flags) 547 int addr_len, int flags)
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index fa24e3f06ac6..13110bee5c14 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -277,15 +277,7 @@ out_rcu_unlock:
277/* bind for INET6 API */ 277/* bind for INET6 API */
278int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) 278int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
279{ 279{
280 struct sockaddr_in6 *addr = (struct sockaddr_in6 *)uaddr;
281 struct sock *sk = sock->sk; 280 struct sock *sk = sock->sk;
282 struct inet_sock *inet = inet_sk(sk);
283 struct ipv6_pinfo *np = inet6_sk(sk);
284 struct net *net = sock_net(sk);
285 __be32 v4addr = 0;
286 unsigned short snum;
287 bool saved_ipv6only;
288 int addr_type = 0;
289 int err = 0; 281 int err = 0;
290 282
291 /* If the socket has its own bind function then use it. */ 283 /* If the socket has its own bind function then use it. */
@@ -302,11 +294,28 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
302 if (err) 294 if (err)
303 return err; 295 return err;
304 296
297 return __inet6_bind(sk, uaddr, addr_len, false, true);
298}
299EXPORT_SYMBOL(inet6_bind);
300
301int __inet6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len,
302 bool force_bind_address_no_port, bool with_lock)
303{
304 struct sockaddr_in6 *addr = (struct sockaddr_in6 *)uaddr;
305 struct inet_sock *inet = inet_sk(sk);
306 struct ipv6_pinfo *np = inet6_sk(sk);
307 struct net *net = sock_net(sk);
308 __be32 v4addr = 0;
309 unsigned short snum;
310 bool saved_ipv6only;
311 int addr_type = 0;
312 int err = 0;
313
305 if (addr->sin6_family != AF_INET6) 314 if (addr->sin6_family != AF_INET6)
306 return -EAFNOSUPPORT; 315 return -EAFNOSUPPORT;
307 316
308 addr_type = ipv6_addr_type(&addr->sin6_addr); 317 addr_type = ipv6_addr_type(&addr->sin6_addr);
309 if ((addr_type & IPV6_ADDR_MULTICAST) && sock->type == SOCK_STREAM) 318 if ((addr_type & IPV6_ADDR_MULTICAST) && sk->sk_type == SOCK_STREAM)
310 return -EINVAL; 319 return -EINVAL;
311 320
312 snum = ntohs(addr->sin6_port); 321 snum = ntohs(addr->sin6_port);
@@ -314,7 +323,8 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
314 !ns_capable(net->user_ns, CAP_NET_BIND_SERVICE)) 323 !ns_capable(net->user_ns, CAP_NET_BIND_SERVICE))
315 return -EACCES; 324 return -EACCES;
316 325
317 lock_sock(sk); 326 if (with_lock)
327 lock_sock(sk);
318 328
319 /* Check these errors (active socket, double bind). */ 329 /* Check these errors (active socket, double bind). */
320 if (sk->sk_state != TCP_CLOSE || inet->inet_num) { 330 if (sk->sk_state != TCP_CLOSE || inet->inet_num) {
@@ -402,7 +412,8 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
402 sk->sk_ipv6only = 1; 412 sk->sk_ipv6only = 1;
403 413
404 /* Make sure we are allowed to bind here. */ 414 /* Make sure we are allowed to bind here. */
405 if ((snum || !inet->bind_address_no_port) && 415 if ((snum || !(inet->bind_address_no_port ||
416 force_bind_address_no_port)) &&
406 sk->sk_prot->get_port(sk, snum)) { 417 sk->sk_prot->get_port(sk, snum)) {
407 sk->sk_ipv6only = saved_ipv6only; 418 sk->sk_ipv6only = saved_ipv6only;
408 inet_reset_saddr(sk); 419 inet_reset_saddr(sk);
@@ -418,13 +429,13 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
418 inet->inet_dport = 0; 429 inet->inet_dport = 0;
419 inet->inet_daddr = 0; 430 inet->inet_daddr = 0;
420out: 431out:
421 release_sock(sk); 432 if (with_lock)
433 release_sock(sk);
422 return err; 434 return err;
423out_unlock: 435out_unlock:
424 rcu_read_unlock(); 436 rcu_read_unlock();
425 goto out; 437 goto out;
426} 438}
427EXPORT_SYMBOL(inet6_bind);
428 439
429int inet6_release(struct socket *sock) 440int inet6_release(struct socket *sock)
430{ 441{