diff options
author | Al Viro <viro@ZenIV.linux.org.uk> | 2017-12-05 18:28:38 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2017-12-05 18:39:28 -0500 |
commit | 016a266bdfeda268afb2228b6217fd4771334635 (patch) | |
tree | f22af8039ab986464ddcb5c7176eb584486d86ca | |
parent | a5739435b5a3b8c449f8844ecd71a3b1e89f0a33 (diff) |
socketpair(): allocate descriptors first
simplifies failure exits considerably...
Reviewed-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | net/socket.c | 89 |
1 files changed, 38 insertions, 51 deletions
diff --git a/net/socket.c b/net/socket.c index 42d8e9c9ccd5..2df83c0bfde9 100644 --- a/net/socket.c +++ b/net/socket.c | |||
@@ -1366,87 +1366,74 @@ SYSCALL_DEFINE4(socketpair, int, family, int, type, int, protocol, | |||
1366 | flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK; | 1366 | flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK; |
1367 | 1367 | ||
1368 | /* | 1368 | /* |
1369 | * reserve descriptors and make sure we won't fail | ||
1370 | * to return them to userland. | ||
1371 | */ | ||
1372 | fd1 = get_unused_fd_flags(flags); | ||
1373 | if (unlikely(fd1 < 0)) | ||
1374 | return fd1; | ||
1375 | |||
1376 | fd2 = get_unused_fd_flags(flags); | ||
1377 | if (unlikely(fd2 < 0)) { | ||
1378 | put_unused_fd(fd1); | ||
1379 | return fd2; | ||
1380 | } | ||
1381 | |||
1382 | err = put_user(fd1, &usockvec[0]); | ||
1383 | if (err) | ||
1384 | goto out; | ||
1385 | |||
1386 | err = put_user(fd2, &usockvec[1]); | ||
1387 | if (err) | ||
1388 | goto out; | ||
1389 | |||
1390 | /* | ||
1369 | * Obtain the first socket and check if the underlying protocol | 1391 | * Obtain the first socket and check if the underlying protocol |
1370 | * supports the socketpair call. | 1392 | * supports the socketpair call. |
1371 | */ | 1393 | */ |
1372 | 1394 | ||
1373 | err = sock_create(family, type, protocol, &sock1); | 1395 | err = sock_create(family, type, protocol, &sock1); |
1374 | if (err < 0) | 1396 | if (unlikely(err < 0)) |
1375 | goto out; | 1397 | goto out; |
1376 | 1398 | ||
1377 | err = sock_create(family, type, protocol, &sock2); | 1399 | err = sock_create(family, type, protocol, &sock2); |
1378 | if (err < 0) | 1400 | if (unlikely(err < 0)) { |
1379 | goto out_release_1; | 1401 | sock_release(sock1); |
1380 | 1402 | goto out; | |
1381 | err = sock1->ops->socketpair(sock1, sock2); | ||
1382 | if (err < 0) | ||
1383 | goto out_release_both; | ||
1384 | |||
1385 | fd1 = get_unused_fd_flags(flags); | ||
1386 | if (unlikely(fd1 < 0)) { | ||
1387 | err = fd1; | ||
1388 | goto out_release_both; | ||
1389 | } | 1403 | } |
1390 | 1404 | ||
1391 | fd2 = get_unused_fd_flags(flags); | 1405 | err = sock1->ops->socketpair(sock1, sock2); |
1392 | if (unlikely(fd2 < 0)) { | 1406 | if (unlikely(err < 0)) { |
1393 | err = fd2; | 1407 | sock_release(sock2); |
1394 | goto out_put_unused_1; | 1408 | sock_release(sock1); |
1409 | goto out; | ||
1395 | } | 1410 | } |
1396 | 1411 | ||
1397 | newfile1 = sock_alloc_file(sock1, flags, NULL); | 1412 | newfile1 = sock_alloc_file(sock1, flags, NULL); |
1398 | if (IS_ERR(newfile1)) { | 1413 | if (IS_ERR(newfile1)) { |
1399 | err = PTR_ERR(newfile1); | 1414 | err = PTR_ERR(newfile1); |
1400 | goto out_put_unused_both; | 1415 | sock_release(sock1); |
1416 | sock_release(sock2); | ||
1417 | goto out; | ||
1401 | } | 1418 | } |
1402 | 1419 | ||
1403 | newfile2 = sock_alloc_file(sock2, flags, NULL); | 1420 | newfile2 = sock_alloc_file(sock2, flags, NULL); |
1404 | if (IS_ERR(newfile2)) { | 1421 | if (IS_ERR(newfile2)) { |
1405 | err = PTR_ERR(newfile2); | 1422 | err = PTR_ERR(newfile2); |
1406 | goto out_fput_1; | 1423 | sock_release(sock2); |
1424 | fput(newfile1); | ||
1425 | goto out; | ||
1407 | } | 1426 | } |
1408 | 1427 | ||
1409 | err = put_user(fd1, &usockvec[0]); | ||
1410 | if (err) | ||
1411 | goto out_fput_both; | ||
1412 | |||
1413 | err = put_user(fd2, &usockvec[1]); | ||
1414 | if (err) | ||
1415 | goto out_fput_both; | ||
1416 | |||
1417 | audit_fd_pair(fd1, fd2); | 1428 | audit_fd_pair(fd1, fd2); |
1418 | 1429 | ||
1419 | fd_install(fd1, newfile1); | 1430 | fd_install(fd1, newfile1); |
1420 | fd_install(fd2, newfile2); | 1431 | fd_install(fd2, newfile2); |
1421 | /* fd1 and fd2 may be already another descriptors. | ||
1422 | * Not kernel problem. | ||
1423 | */ | ||
1424 | |||
1425 | return 0; | 1432 | return 0; |
1426 | 1433 | ||
1427 | out_fput_both: | 1434 | out: |
1428 | fput(newfile2); | ||
1429 | fput(newfile1); | ||
1430 | put_unused_fd(fd2); | ||
1431 | put_unused_fd(fd1); | ||
1432 | goto out; | ||
1433 | |||
1434 | out_fput_1: | ||
1435 | fput(newfile1); | ||
1436 | put_unused_fd(fd2); | ||
1437 | put_unused_fd(fd1); | ||
1438 | sock_release(sock2); | ||
1439 | goto out; | ||
1440 | |||
1441 | out_put_unused_both: | ||
1442 | put_unused_fd(fd2); | 1435 | put_unused_fd(fd2); |
1443 | out_put_unused_1: | ||
1444 | put_unused_fd(fd1); | 1436 | put_unused_fd(fd1); |
1445 | out_release_both: | ||
1446 | sock_release(sock2); | ||
1447 | out_release_1: | ||
1448 | sock_release(sock1); | ||
1449 | out: | ||
1450 | return err; | 1437 | return err; |
1451 | } | 1438 | } |
1452 | 1439 | ||