aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/socket.c192
1 files changed, 106 insertions, 86 deletions
diff --git a/net/socket.c b/net/socket.c
index 74283610db15..510ae18d220a 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -426,6 +426,28 @@ int sock_map_fd(struct socket *sock)
426 return fd; 426 return fd;
427} 427}
428 428
429static struct socket *sock_from_file(struct file *file, int *err)
430{
431 struct inode *inode;
432 struct socket *sock;
433
434 if (file->f_op == &socket_file_ops)
435 return file->private_data; /* set in sock_map_fd */
436
437 inode = file->f_dentry->d_inode;
438 if (!S_ISSOCK(inode->i_mode)) {
439 *err = -ENOTSOCK;
440 return NULL;
441 }
442
443 sock = SOCKET_I(inode);
444 if (sock->file != file) {
445 printk(KERN_ERR "socki_lookup: socket file changed!\n");
446 sock->file = file;
447 }
448 return sock;
449}
450
429/** 451/**
430 * sockfd_lookup - Go from a file number to its socket slot 452 * sockfd_lookup - Go from a file number to its socket slot
431 * @fd: file handle 453 * @fd: file handle
@@ -442,31 +464,31 @@ int sock_map_fd(struct socket *sock)
442struct socket *sockfd_lookup(int fd, int *err) 464struct socket *sockfd_lookup(int fd, int *err)
443{ 465{
444 struct file *file; 466 struct file *file;
445 struct inode *inode;
446 struct socket *sock; 467 struct socket *sock;
447 468
448 if (!(file = fget(fd))) 469 if (!(file = fget(fd))) {
449 {
450 *err = -EBADF; 470 *err = -EBADF;
451 return NULL; 471 return NULL;
452 } 472 }
453 473 sock = sock_from_file(file, err);
454 if (file->f_op == &socket_file_ops) 474 if (!sock)
455 return file->private_data; /* set in sock_map_fd */
456
457 inode = file->f_dentry->d_inode;
458 if (!S_ISSOCK(inode->i_mode)) {
459 *err = -ENOTSOCK;
460 fput(file); 475 fput(file);
461 return NULL; 476 return sock;
462 } 477}
463 478
464 sock = SOCKET_I(inode); 479static struct socket *sockfd_lookup_light(int fd, int *err, int *fput_needed)
465 if (sock->file != file) { 480{
466 printk(KERN_ERR "socki_lookup: socket file changed!\n"); 481 struct file *file;
467 sock->file = file; 482 struct socket *sock;
483
484 file = fget_light(fd, fput_needed);
485 if (file) {
486 sock = sock_from_file(file, err);
487 if (sock)
488 return sock;
489 fput_light(file, *fput_needed);
468 } 490 }
469 return sock; 491 return NULL;
470} 492}
471 493
472/** 494/**
@@ -1301,19 +1323,17 @@ asmlinkage long sys_bind(int fd, struct sockaddr __user *umyaddr, int addrlen)
1301{ 1323{
1302 struct socket *sock; 1324 struct socket *sock;
1303 char address[MAX_SOCK_ADDR]; 1325 char address[MAX_SOCK_ADDR];
1304 int err; 1326 int err, fput_needed;
1305 1327
1306 if((sock = sockfd_lookup(fd,&err))!=NULL) 1328 if((sock = sockfd_lookup_light(fd, &err, &fput_needed))!=NULL)
1307 { 1329 {
1308 if((err=move_addr_to_kernel(umyaddr,addrlen,address))>=0) { 1330 if((err=move_addr_to_kernel(umyaddr,addrlen,address))>=0) {
1309 err = security_socket_bind(sock, (struct sockaddr *)address, addrlen); 1331 err = security_socket_bind(sock, (struct sockaddr *)address, addrlen);
1310 if (err) { 1332 if (!err)
1311 sockfd_put(sock); 1333 err = sock->ops->bind(sock,
1312 return err; 1334 (struct sockaddr *)address, addrlen);
1313 }
1314 err = sock->ops->bind(sock, (struct sockaddr *)address, addrlen);
1315 } 1335 }
1316 sockfd_put(sock); 1336 fput_light(sock->file, fput_needed);
1317 } 1337 }
1318 return err; 1338 return err;
1319} 1339}
@@ -1330,20 +1350,17 @@ int sysctl_somaxconn = SOMAXCONN;
1330asmlinkage long sys_listen(int fd, int backlog) 1350asmlinkage long sys_listen(int fd, int backlog)
1331{ 1351{
1332 struct socket *sock; 1352 struct socket *sock;
1333 int err; 1353 int err, fput_needed;
1334 1354
1335 if ((sock = sockfd_lookup(fd, &err)) != NULL) { 1355 if ((sock = sockfd_lookup_light(fd, &err, &fput_needed)) != NULL) {
1336 if ((unsigned) backlog > sysctl_somaxconn) 1356 if ((unsigned) backlog > sysctl_somaxconn)
1337 backlog = sysctl_somaxconn; 1357 backlog = sysctl_somaxconn;
1338 1358
1339 err = security_socket_listen(sock, backlog); 1359 err = security_socket_listen(sock, backlog);
1340 if (err) { 1360 if (!err)
1341 sockfd_put(sock); 1361 err = sock->ops->listen(sock, backlog);
1342 return err;
1343 }
1344 1362
1345 err=sock->ops->listen(sock, backlog); 1363 fput_light(sock->file, fput_needed);
1346 sockfd_put(sock);
1347 } 1364 }
1348 return err; 1365 return err;
1349} 1366}
@@ -1365,10 +1382,10 @@ asmlinkage long sys_accept(int fd, struct sockaddr __user *upeer_sockaddr, int _
1365{ 1382{
1366 struct socket *sock, *newsock; 1383 struct socket *sock, *newsock;
1367 struct file *newfile; 1384 struct file *newfile;
1368 int err, len, newfd; 1385 int err, len, newfd, fput_needed;
1369 char address[MAX_SOCK_ADDR]; 1386 char address[MAX_SOCK_ADDR];
1370 1387
1371 sock = sockfd_lookup(fd, &err); 1388 sock = sockfd_lookup_light(fd, &err, &fput_needed);
1372 if (!sock) 1389 if (!sock)
1373 goto out; 1390 goto out;
1374 1391
@@ -1421,7 +1438,7 @@ asmlinkage long sys_accept(int fd, struct sockaddr __user *upeer_sockaddr, int _
1421 security_socket_post_accept(sock, newsock); 1438 security_socket_post_accept(sock, newsock);
1422 1439
1423out_put: 1440out_put:
1424 sockfd_put(sock); 1441 fput_light(sock->file, fput_needed);
1425out: 1442out:
1426 return err; 1443 return err;
1427out_fd: 1444out_fd:
@@ -1449,9 +1466,9 @@ asmlinkage long sys_connect(int fd, struct sockaddr __user *uservaddr, int addrl
1449{ 1466{
1450 struct socket *sock; 1467 struct socket *sock;
1451 char address[MAX_SOCK_ADDR]; 1468 char address[MAX_SOCK_ADDR];
1452 int err; 1469 int err, fput_needed;
1453 1470
1454 sock = sockfd_lookup(fd, &err); 1471 sock = sockfd_lookup_light(fd, &err, &fput_needed);
1455 if (!sock) 1472 if (!sock)
1456 goto out; 1473 goto out;
1457 err = move_addr_to_kernel(uservaddr, addrlen, address); 1474 err = move_addr_to_kernel(uservaddr, addrlen, address);
@@ -1465,7 +1482,7 @@ asmlinkage long sys_connect(int fd, struct sockaddr __user *uservaddr, int addrl
1465 err = sock->ops->connect(sock, (struct sockaddr *) address, addrlen, 1482 err = sock->ops->connect(sock, (struct sockaddr *) address, addrlen,
1466 sock->file->f_flags); 1483 sock->file->f_flags);
1467out_put: 1484out_put:
1468 sockfd_put(sock); 1485 fput_light(sock->file, fput_needed);
1469out: 1486out:
1470 return err; 1487 return err;
1471} 1488}
@@ -1479,9 +1496,9 @@ asmlinkage long sys_getsockname(int fd, struct sockaddr __user *usockaddr, int _
1479{ 1496{
1480 struct socket *sock; 1497 struct socket *sock;
1481 char address[MAX_SOCK_ADDR]; 1498 char address[MAX_SOCK_ADDR];
1482 int len, err; 1499 int len, err, fput_needed;
1483 1500
1484 sock = sockfd_lookup(fd, &err); 1501 sock = sockfd_lookup_light(fd, &err, &fput_needed);
1485 if (!sock) 1502 if (!sock)
1486 goto out; 1503 goto out;
1487 1504
@@ -1495,7 +1512,7 @@ asmlinkage long sys_getsockname(int fd, struct sockaddr __user *usockaddr, int _
1495 err = move_addr_to_user(address, len, usockaddr, usockaddr_len); 1512 err = move_addr_to_user(address, len, usockaddr, usockaddr_len);
1496 1513
1497out_put: 1514out_put:
1498 sockfd_put(sock); 1515 fput_light(sock->file, fput_needed);
1499out: 1516out:
1500 return err; 1517 return err;
1501} 1518}
@@ -1509,20 +1526,19 @@ asmlinkage long sys_getpeername(int fd, struct sockaddr __user *usockaddr, int _
1509{ 1526{
1510 struct socket *sock; 1527 struct socket *sock;
1511 char address[MAX_SOCK_ADDR]; 1528 char address[MAX_SOCK_ADDR];
1512 int len, err; 1529 int len, err, fput_needed;
1513 1530
1514 if ((sock = sockfd_lookup(fd, &err))!=NULL) 1531 if ((sock = sockfd_lookup_light(fd, &err, &fput_needed)) != NULL) {
1515 {
1516 err = security_socket_getpeername(sock); 1532 err = security_socket_getpeername(sock);
1517 if (err) { 1533 if (err) {
1518 sockfd_put(sock); 1534 fput_light(sock->file, fput_needed);
1519 return err; 1535 return err;
1520 } 1536 }
1521 1537
1522 err = sock->ops->getname(sock, (struct sockaddr *)address, &len, 1); 1538 err = sock->ops->getname(sock, (struct sockaddr *)address, &len, 1);
1523 if (!err) 1539 if (!err)
1524 err=move_addr_to_user(address,len, usockaddr, usockaddr_len); 1540 err=move_addr_to_user(address,len, usockaddr, usockaddr_len);
1525 sockfd_put(sock); 1541 fput_light(sock->file, fput_needed);
1526 } 1542 }
1527 return err; 1543 return err;
1528} 1544}
@@ -1541,10 +1557,16 @@ asmlinkage long sys_sendto(int fd, void __user * buff, size_t len, unsigned flag
1541 int err; 1557 int err;
1542 struct msghdr msg; 1558 struct msghdr msg;
1543 struct iovec iov; 1559 struct iovec iov;
1544 1560 int fput_needed;
1545 sock = sockfd_lookup(fd, &err); 1561 struct file *sock_file;
1562
1563 sock_file = fget_light(fd, &fput_needed);
1564 if (!sock_file)
1565 return -EBADF;
1566
1567 sock = sock_from_file(sock_file, &err);
1546 if (!sock) 1568 if (!sock)
1547 goto out; 1569 goto out_put;
1548 iov.iov_base=buff; 1570 iov.iov_base=buff;
1549 iov.iov_len=len; 1571 iov.iov_len=len;
1550 msg.msg_name=NULL; 1572 msg.msg_name=NULL;
@@ -1553,8 +1575,7 @@ asmlinkage long sys_sendto(int fd, void __user * buff, size_t len, unsigned flag
1553 msg.msg_control=NULL; 1575 msg.msg_control=NULL;
1554 msg.msg_controllen=0; 1576 msg.msg_controllen=0;
1555 msg.msg_namelen=0; 1577 msg.msg_namelen=0;
1556 if(addr) 1578 if (addr) {
1557 {
1558 err = move_addr_to_kernel(addr, addr_len, address); 1579 err = move_addr_to_kernel(addr, addr_len, address);
1559 if (err < 0) 1580 if (err < 0)
1560 goto out_put; 1581 goto out_put;
@@ -1567,8 +1588,7 @@ asmlinkage long sys_sendto(int fd, void __user * buff, size_t len, unsigned flag
1567 err = sock_sendmsg(sock, &msg, len); 1588 err = sock_sendmsg(sock, &msg, len);
1568 1589
1569out_put: 1590out_put:
1570 sockfd_put(sock); 1591 fput_light(sock_file, fput_needed);
1571out:
1572 return err; 1592 return err;
1573} 1593}
1574 1594
@@ -1595,8 +1615,14 @@ asmlinkage long sys_recvfrom(int fd, void __user * ubuf, size_t size, unsigned f
1595 struct msghdr msg; 1615 struct msghdr msg;
1596 char address[MAX_SOCK_ADDR]; 1616 char address[MAX_SOCK_ADDR];
1597 int err,err2; 1617 int err,err2;
1618 struct file *sock_file;
1619 int fput_needed;
1620
1621 sock_file = fget_light(fd, &fput_needed);
1622 if (!sock_file)
1623 return -EBADF;
1598 1624
1599 sock = sockfd_lookup(fd, &err); 1625 sock = sock_from_file(sock_file, &err);
1600 if (!sock) 1626 if (!sock)
1601 goto out; 1627 goto out;
1602 1628
@@ -1618,8 +1644,8 @@ asmlinkage long sys_recvfrom(int fd, void __user * ubuf, size_t size, unsigned f
1618 if(err2<0) 1644 if(err2<0)
1619 err=err2; 1645 err=err2;
1620 } 1646 }
1621 sockfd_put(sock);
1622out: 1647out:
1648 fput_light(sock_file, fput_needed);
1623 return err; 1649 return err;
1624} 1650}
1625 1651
@@ -1639,25 +1665,24 @@ asmlinkage long sys_recv(int fd, void __user * ubuf, size_t size, unsigned flags
1639 1665
1640asmlinkage long sys_setsockopt(int fd, int level, int optname, char __user *optval, int optlen) 1666asmlinkage long sys_setsockopt(int fd, int level, int optname, char __user *optval, int optlen)
1641{ 1667{
1642 int err; 1668 int err, fput_needed;
1643 struct socket *sock; 1669 struct socket *sock;
1644 1670
1645 if (optlen < 0) 1671 if (optlen < 0)
1646 return -EINVAL; 1672 return -EINVAL;
1647 1673
1648 if ((sock = sockfd_lookup(fd, &err))!=NULL) 1674 if ((sock = sockfd_lookup_light(fd, &err, &fput_needed)) != NULL)
1649 { 1675 {
1650 err = security_socket_setsockopt(sock,level,optname); 1676 err = security_socket_setsockopt(sock,level,optname);
1651 if (err) { 1677 if (err)
1652 sockfd_put(sock); 1678 goto out_put;
1653 return err;
1654 }
1655 1679
1656 if (level == SOL_SOCKET) 1680 if (level == SOL_SOCKET)
1657 err=sock_setsockopt(sock,level,optname,optval,optlen); 1681 err=sock_setsockopt(sock,level,optname,optval,optlen);
1658 else 1682 else
1659 err=sock->ops->setsockopt(sock, level, optname, optval, optlen); 1683 err=sock->ops->setsockopt(sock, level, optname, optval, optlen);
1660 sockfd_put(sock); 1684out_put:
1685 fput_light(sock->file, fput_needed);
1661 } 1686 }
1662 return err; 1687 return err;
1663} 1688}
@@ -1669,23 +1694,20 @@ asmlinkage long sys_setsockopt(int fd, int level, int optname, char __user *optv
1669 1694
1670asmlinkage long sys_getsockopt(int fd, int level, int optname, char __user *optval, int __user *optlen) 1695asmlinkage long sys_getsockopt(int fd, int level, int optname, char __user *optval, int __user *optlen)
1671{ 1696{
1672 int err; 1697 int err, fput_needed;
1673 struct socket *sock; 1698 struct socket *sock;
1674 1699
1675 if ((sock = sockfd_lookup(fd, &err))!=NULL) 1700 if ((sock = sockfd_lookup_light(fd, &err, &fput_needed)) != NULL) {
1676 { 1701 err = security_socket_getsockopt(sock, level, optname);
1677 err = security_socket_getsockopt(sock, level, 1702 if (err)
1678 optname); 1703 goto out_put;
1679 if (err) {
1680 sockfd_put(sock);
1681 return err;
1682 }
1683 1704
1684 if (level == SOL_SOCKET) 1705 if (level == SOL_SOCKET)
1685 err=sock_getsockopt(sock,level,optname,optval,optlen); 1706 err=sock_getsockopt(sock,level,optname,optval,optlen);
1686 else 1707 else
1687 err=sock->ops->getsockopt(sock, level, optname, optval, optlen); 1708 err=sock->ops->getsockopt(sock, level, optname, optval, optlen);
1688 sockfd_put(sock); 1709out_put:
1710 fput_light(sock->file, fput_needed);
1689 } 1711 }
1690 return err; 1712 return err;
1691} 1713}
@@ -1697,19 +1719,15 @@ asmlinkage long sys_getsockopt(int fd, int level, int optname, char __user *optv
1697 1719
1698asmlinkage long sys_shutdown(int fd, int how) 1720asmlinkage long sys_shutdown(int fd, int how)
1699{ 1721{
1700 int err; 1722 int err, fput_needed;
1701 struct socket *sock; 1723 struct socket *sock;
1702 1724
1703 if ((sock = sockfd_lookup(fd, &err))!=NULL) 1725 if ((sock = sockfd_lookup_light(fd, &err, &fput_needed))!=NULL)
1704 { 1726 {
1705 err = security_socket_shutdown(sock, how); 1727 err = security_socket_shutdown(sock, how);
1706 if (err) { 1728 if (!err)
1707 sockfd_put(sock); 1729 err = sock->ops->shutdown(sock, how);
1708 return err; 1730 fput_light(sock->file, fput_needed);
1709 }
1710
1711 err=sock->ops->shutdown(sock, how);
1712 sockfd_put(sock);
1713 } 1731 }
1714 return err; 1732 return err;
1715} 1733}
@@ -1738,6 +1756,7 @@ asmlinkage long sys_sendmsg(int fd, struct msghdr __user *msg, unsigned flags)
1738 unsigned char *ctl_buf = ctl; 1756 unsigned char *ctl_buf = ctl;
1739 struct msghdr msg_sys; 1757 struct msghdr msg_sys;
1740 int err, ctl_len, iov_size, total_len; 1758 int err, ctl_len, iov_size, total_len;
1759 int fput_needed;
1741 1760
1742 err = -EFAULT; 1761 err = -EFAULT;
1743 if (MSG_CMSG_COMPAT & flags) { 1762 if (MSG_CMSG_COMPAT & flags) {
@@ -1746,7 +1765,7 @@ asmlinkage long sys_sendmsg(int fd, struct msghdr __user *msg, unsigned flags)
1746 } else if (copy_from_user(&msg_sys, msg, sizeof(struct msghdr))) 1765 } else if (copy_from_user(&msg_sys, msg, sizeof(struct msghdr)))
1747 return -EFAULT; 1766 return -EFAULT;
1748 1767
1749 sock = sockfd_lookup(fd, &err); 1768 sock = sockfd_lookup_light(fd, &err, &fput_needed);
1750 if (!sock) 1769 if (!sock)
1751 goto out; 1770 goto out;
1752 1771
@@ -1814,7 +1833,7 @@ out_freeiov:
1814 if (iov != iovstack) 1833 if (iov != iovstack)
1815 sock_kfree_s(sock->sk, iov, iov_size); 1834 sock_kfree_s(sock->sk, iov, iov_size);
1816out_put: 1835out_put:
1817 sockfd_put(sock); 1836 fput_light(sock->file, fput_needed);
1818out: 1837out:
1819 return err; 1838 return err;
1820} 1839}
@@ -1832,6 +1851,7 @@ asmlinkage long sys_recvmsg(int fd, struct msghdr __user *msg, unsigned int flag
1832 struct msghdr msg_sys; 1851 struct msghdr msg_sys;
1833 unsigned long cmsg_ptr; 1852 unsigned long cmsg_ptr;
1834 int err, iov_size, total_len, len; 1853 int err, iov_size, total_len, len;
1854 int fput_needed;
1835 1855
1836 /* kernel mode address */ 1856 /* kernel mode address */
1837 char addr[MAX_SOCK_ADDR]; 1857 char addr[MAX_SOCK_ADDR];
@@ -1847,7 +1867,7 @@ asmlinkage long sys_recvmsg(int fd, struct msghdr __user *msg, unsigned int flag
1847 if (copy_from_user(&msg_sys,msg,sizeof(struct msghdr))) 1867 if (copy_from_user(&msg_sys,msg,sizeof(struct msghdr)))
1848 return -EFAULT; 1868 return -EFAULT;
1849 1869
1850 sock = sockfd_lookup(fd, &err); 1870 sock = sockfd_lookup_light(fd, &err, &fput_needed);
1851 if (!sock) 1871 if (!sock)
1852 goto out; 1872 goto out;
1853 1873
@@ -1914,7 +1934,7 @@ out_freeiov:
1914 if (iov != iovstack) 1934 if (iov != iovstack)
1915 sock_kfree_s(sock->sk, iov, iov_size); 1935 sock_kfree_s(sock->sk, iov, iov_size);
1916out_put: 1936out_put:
1917 sockfd_put(sock); 1937 fput_light(sock->file, fput_needed);
1918out: 1938out:
1919 return err; 1939 return err;
1920} 1940}