aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorStephen Hemminger <shemminger@linux-foundation.org>2007-10-10 20:30:46 -0400
committerDavid S. Miller <davem@davemloft.net>2007-10-10 20:30:46 -0400
commit227b60f5102cda4e4ab792b526a59c8cb20cd9f8 (patch)
tree2c9e372601ba794894833b0618bc531a9f5d57c4 /drivers
parent06393009000779b00a558fd2f280882cc7dc2008 (diff)
[INET]: local port range robustness
Expansion of original idea from Denis V. Lunev <den@openvz.org> Add robustness and locking to the local_port_range sysctl. 1. Enforce that low < high when setting. 2. Use seqlock to ensure atomic update. The locking might seem like overkill, but there are cases where sysadmin might want to change value in the middle of a DoS attack. Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/infiniband/core/cma.c22
1 files changed, 12 insertions, 10 deletions
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
index 9ffb9987450a..2e641b255db4 100644
--- a/drivers/infiniband/core/cma.c
+++ b/drivers/infiniband/core/cma.c
@@ -1866,13 +1866,14 @@ err1:
1866static int cma_alloc_any_port(struct idr *ps, struct rdma_id_private *id_priv) 1866static int cma_alloc_any_port(struct idr *ps, struct rdma_id_private *id_priv)
1867{ 1867{
1868 struct rdma_bind_list *bind_list; 1868 struct rdma_bind_list *bind_list;
1869 int port, ret; 1869 int port, ret, low, high;
1870 1870
1871 bind_list = kzalloc(sizeof *bind_list, GFP_KERNEL); 1871 bind_list = kzalloc(sizeof *bind_list, GFP_KERNEL);
1872 if (!bind_list) 1872 if (!bind_list)
1873 return -ENOMEM; 1873 return -ENOMEM;
1874 1874
1875retry: 1875retry:
1876 /* FIXME: add proper port randomization per like inet_csk_get_port */
1876 do { 1877 do {
1877 ret = idr_get_new_above(ps, bind_list, next_port, &port); 1878 ret = idr_get_new_above(ps, bind_list, next_port, &port);
1878 } while ((ret == -EAGAIN) && idr_pre_get(ps, GFP_KERNEL)); 1879 } while ((ret == -EAGAIN) && idr_pre_get(ps, GFP_KERNEL));
@@ -1880,18 +1881,19 @@ retry:
1880 if (ret) 1881 if (ret)
1881 goto err1; 1882 goto err1;
1882 1883
1883 if (port > sysctl_local_port_range[1]) { 1884 inet_get_local_port_range(&low, &high);
1884 if (next_port != sysctl_local_port_range[0]) { 1885 if (port > high) {
1886 if (next_port != low) {
1885 idr_remove(ps, port); 1887 idr_remove(ps, port);
1886 next_port = sysctl_local_port_range[0]; 1888 next_port = low;
1887 goto retry; 1889 goto retry;
1888 } 1890 }
1889 ret = -EADDRNOTAVAIL; 1891 ret = -EADDRNOTAVAIL;
1890 goto err2; 1892 goto err2;
1891 } 1893 }
1892 1894
1893 if (port == sysctl_local_port_range[1]) 1895 if (port == high)
1894 next_port = sysctl_local_port_range[0]; 1896 next_port = low;
1895 else 1897 else
1896 next_port = port + 1; 1898 next_port = port + 1;
1897 1899
@@ -2769,12 +2771,12 @@ static void cma_remove_one(struct ib_device *device)
2769 2771
2770static int cma_init(void) 2772static int cma_init(void)
2771{ 2773{
2772 int ret; 2774 int ret, low, high;
2773 2775
2774 get_random_bytes(&next_port, sizeof next_port); 2776 get_random_bytes(&next_port, sizeof next_port);
2775 next_port = ((unsigned int) next_port % 2777 inet_get_local_port_range(&low, &high);
2776 (sysctl_local_port_range[1] - sysctl_local_port_range[0])) + 2778 next_port = ((unsigned int) next_port % (high - low)) + low;
2777 sysctl_local_port_range[0]; 2779
2778 cma_wq = create_singlethread_workqueue("rdma_cm"); 2780 cma_wq = create_singlethread_workqueue("rdma_cm");
2779 if (!cma_wq) 2781 if (!cma_wq)
2780 return -ENOMEM; 2782 return -ENOMEM;