Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 67054
b: refs/heads/master
c: 227b60f
h: refs/heads/master
v: v3
  • Loading branch information
Stephen Hemminger authored and David S. Miller committed Oct 11, 2007
1 parent 413ff5c commit 3dfea98
Show file tree
Hide file tree
Showing 11 changed files with 147 additions and 59 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 06393009000779b00a558fd2f280882cc7dc2008
refs/heads/master: 227b60f5102cda4e4ab792b526a59c8cb20cd9f8
22 changes: 12 additions & 10 deletions trunk/drivers/infiniband/core/cma.c
Original file line number Diff line number Diff line change
Expand Up @@ -1866,32 +1866,34 @@ static int cma_alloc_port(struct idr *ps, struct rdma_id_private *id_priv,
static int cma_alloc_any_port(struct idr *ps, struct rdma_id_private *id_priv)
{
struct rdma_bind_list *bind_list;
int port, ret;
int port, ret, low, high;

bind_list = kzalloc(sizeof *bind_list, GFP_KERNEL);
if (!bind_list)
return -ENOMEM;

retry:
/* FIXME: add proper port randomization per like inet_csk_get_port */
do {
ret = idr_get_new_above(ps, bind_list, next_port, &port);
} while ((ret == -EAGAIN) && idr_pre_get(ps, GFP_KERNEL));

if (ret)
goto err1;

if (port > sysctl_local_port_range[1]) {
if (next_port != sysctl_local_port_range[0]) {
inet_get_local_port_range(&low, &high);
if (port > high) {
if (next_port != low) {
idr_remove(ps, port);
next_port = sysctl_local_port_range[0];
next_port = low;
goto retry;
}
ret = -EADDRNOTAVAIL;
goto err2;
}

if (port == sysctl_local_port_range[1])
next_port = sysctl_local_port_range[0];
if (port == high)
next_port = low;
else
next_port = port + 1;

Expand Down Expand Up @@ -2769,12 +2771,12 @@ static void cma_remove_one(struct ib_device *device)

static int cma_init(void)
{
int ret;
int ret, low, high;

get_random_bytes(&next_port, sizeof next_port);
next_port = ((unsigned int) next_port %
(sysctl_local_port_range[1] - sysctl_local_port_range[0])) +
sysctl_local_port_range[0];
inet_get_local_port_range(&low, &high);
next_port = ((unsigned int) next_port % (high - low)) + low;

cma_wq = create_singlethread_workqueue("rdma_cm");
if (!cma_wq)
return -ENOMEM;
Expand Down
3 changes: 2 additions & 1 deletion trunk/include/net/ip.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,8 @@ extern unsigned long snmp_fold_field(void *mib[], int offt);
extern int snmp_mib_init(void *ptr[2], size_t mibsize, size_t mibalign);
extern void snmp_mib_free(void *ptr[2]);

extern int sysctl_local_port_range[2];
extern void inet_get_local_port_range(int *low, int *high);

extern int sysctl_ip_default_ttl;
extern int sysctl_ip_nonlocal_bind;

Expand Down
22 changes: 18 additions & 4 deletions trunk/net/ipv4/inet_connection_sock.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,19 @@ EXPORT_SYMBOL(inet_csk_timer_bug_msg);
* This array holds the first and last local port number.
*/
int sysctl_local_port_range[2] = { 32768, 61000 };
DEFINE_SEQLOCK(sysctl_port_range_lock);

void inet_get_local_port_range(int *low, int *high)
{
unsigned seq;
do {
seq = read_seqbegin(&sysctl_port_range_lock);

*low = sysctl_local_port_range[0];
*high = sysctl_local_port_range[1];
} while (read_seqretry(&sysctl_port_range_lock, seq));
}
EXPORT_SYMBOL(inet_get_local_port_range);

int inet_csk_bind_conflict(const struct sock *sk,
const struct inet_bind_bucket *tb)
Expand Down Expand Up @@ -77,10 +90,11 @@ int inet_csk_get_port(struct inet_hashinfo *hashinfo,

local_bh_disable();
if (!snum) {
int low = sysctl_local_port_range[0];
int high = sysctl_local_port_range[1];
int remaining = (high - low) + 1;
int rover = net_random() % (high - low) + low;
int remaining, rover, low, high;

inet_get_local_port_range(&low, &high);
remaining = high - low;
rover = net_random() % remaining + low;

do {
head = &hashinfo->bhash[inet_bhashfn(rover, hashinfo->bhash_size)];
Expand Down
13 changes: 6 additions & 7 deletions trunk/net/ipv4/inet_hashtables.c
Original file line number Diff line number Diff line change
Expand Up @@ -279,19 +279,18 @@ int inet_hash_connect(struct inet_timewait_death_row *death_row,
int ret;

if (!snum) {
int low = sysctl_local_port_range[0];
int high = sysctl_local_port_range[1];
int range = high - low;
int i;
int port;
int i, remaining, low, high, port;
static u32 hint;
u32 offset = hint + inet_sk_port_offset(sk);
struct hlist_node *node;
struct inet_timewait_sock *tw = NULL;

inet_get_local_port_range(&low, &high);
remaining = high - low;

local_bh_disable();
for (i = 1; i <= range; i++) {
port = low + (i + offset) % range;
for (i = 1; i <= remaining; i++) {
port = low + (i + offset) % remaining;
head = &hinfo->bhash[inet_bhashfn(port, hinfo->bhash_size)];
spin_lock(&head->lock);

Expand Down
75 changes: 71 additions & 4 deletions trunk/net/ipv4/sysctl_net_ipv4.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <linux/sysctl.h>
#include <linux/igmp.h>
#include <linux/inetdevice.h>
#include <linux/seqlock.h>
#include <net/snmp.h>
#include <net/icmp.h>
#include <net/ip.h>
Expand Down Expand Up @@ -89,6 +90,74 @@ static int ipv4_sysctl_forward_strategy(ctl_table *table,
return 1;
}

extern seqlock_t sysctl_port_range_lock;
extern int sysctl_local_port_range[2];

/* Update system visible IP port range */
static void set_local_port_range(int range[2])
{
write_seqlock(&sysctl_port_range_lock);
sysctl_local_port_range[0] = range[0];
sysctl_local_port_range[1] = range[1];
write_sequnlock(&sysctl_port_range_lock);
}

/* Validate changes from /proc interface. */
static int ipv4_local_port_range(ctl_table *table, int write, struct file *filp,
void __user *buffer,
size_t *lenp, loff_t *ppos)
{
int ret;
int range[2] = { sysctl_local_port_range[0],
sysctl_local_port_range[1] };
ctl_table tmp = {
.data = &range,
.maxlen = sizeof(range),
.mode = table->mode,
.extra1 = &ip_local_port_range_min,
.extra2 = &ip_local_port_range_max,
};

ret = proc_dointvec_minmax(&tmp, write, filp, buffer, lenp, ppos);

if (write && ret == 0) {
if (range[1] <= range[0])
ret = -EINVAL;
else
set_local_port_range(range);
}

return ret;
}

/* Validate changes from sysctl interface. */
static int ipv4_sysctl_local_port_range(ctl_table *table, int __user *name,
int nlen, void __user *oldval,
size_t __user *oldlenp,
void __user *newval, size_t newlen)
{
int ret;
int range[2] = { sysctl_local_port_range[0],
sysctl_local_port_range[1] };
ctl_table tmp = {
.data = &range,
.maxlen = sizeof(range),
.mode = table->mode,
.extra1 = &ip_local_port_range_min,
.extra2 = &ip_local_port_range_max,
};

ret = sysctl_intvec(&tmp, name, nlen, oldval, oldlenp, newval, newlen);
if (ret == 0 && newval && newlen) {
if (range[1] <= range[0])
ret = -EINVAL;
else
set_local_port_range(range);
}
return ret;
}


static int proc_tcp_congestion_control(ctl_table *ctl, int write, struct file * filp,
void __user *buffer, size_t *lenp, loff_t *ppos)
{
Expand Down Expand Up @@ -427,10 +496,8 @@ ctl_table ipv4_table[] = {
.data = &sysctl_local_port_range,
.maxlen = sizeof(sysctl_local_port_range),
.mode = 0644,
.proc_handler = &proc_dointvec_minmax,
.strategy = &sysctl_intvec,
.extra1 = ip_local_port_range_min,
.extra2 = ip_local_port_range_max
.proc_handler = &ipv4_local_port_range,
.strategy = &ipv4_sysctl_local_port_range,
},
{
.ctl_name = NET_IPV4_ICMP_ECHO_IGNORE_ALL,
Expand Down
1 change: 0 additions & 1 deletion trunk/net/ipv4/tcp_ipv4.c
Original file line number Diff line number Diff line change
Expand Up @@ -2470,6 +2470,5 @@ EXPORT_SYMBOL(tcp_v4_syn_recv_sock);
EXPORT_SYMBOL(tcp_proc_register);
EXPORT_SYMBOL(tcp_proc_unregister);
#endif
EXPORT_SYMBOL(sysctl_local_port_range);
EXPORT_SYMBOL(sysctl_tcp_low_latency);

6 changes: 3 additions & 3 deletions trunk/net/ipv4/udp.c
Original file line number Diff line number Diff line change
Expand Up @@ -147,11 +147,11 @@ int __udp_lib_get_port(struct sock *sk, unsigned short snum,
write_lock_bh(&udp_hash_lock);

if (!snum) {
int i;
int low = sysctl_local_port_range[0];
int high = sysctl_local_port_range[1];
int i, low, high;
unsigned rover, best, best_size_so_far;

inet_get_local_port_range(&low, &high);

best_size_so_far = UINT_MAX;
best = rover = net_random() % (high - low) + low;

Expand Down
12 changes: 6 additions & 6 deletions trunk/net/ipv6/inet6_hashtables.c
Original file line number Diff line number Diff line change
Expand Up @@ -254,18 +254,18 @@ int inet6_hash_connect(struct inet_timewait_death_row *death_row,
int ret;

if (snum == 0) {
const int low = sysctl_local_port_range[0];
const int high = sysctl_local_port_range[1];
const int range = high - low;
int i, port;
int i, port, low, high, remaining;
static u32 hint;
const u32 offset = hint + inet6_sk_port_offset(sk);
struct hlist_node *node;
struct inet_timewait_sock *tw = NULL;

inet_get_local_port_range(&low, &high);
remaining = high - low;

local_bh_disable();
for (i = 1; i <= range; i++) {
port = low + (i + offset) % range;
for (i = 1; i <= remaining; i++) {
port = low + (i + offset) % remaining;
head = &hinfo->bhash[inet_bhashfn(port, hinfo->bhash_size)];
spin_lock(&head->lock);

Expand Down
11 changes: 6 additions & 5 deletions trunk/net/sctp/socket.c
Original file line number Diff line number Diff line change
Expand Up @@ -5315,11 +5315,12 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr)

if (snum == 0) {
/* Search for an available port. */
unsigned int low = sysctl_local_port_range[0];
unsigned int high = sysctl_local_port_range[1];
unsigned int remaining = (high - low) + 1;
unsigned int rover = net_random() % remaining + low;
int index;
int low, high, remaining, index;
unsigned int rover;

inet_get_local_port_range(&low, &high);
remaining = (high - low) + 1;
rover = net_random() % remaining + low;

do {
rover++;
Expand Down
39 changes: 22 additions & 17 deletions trunk/security/selinux/hooks.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
#include <linux/netfilter_ipv6.h>
#include <linux/tty.h>
#include <net/icmp.h>
#include <net/ip.h> /* for sysctl_local_port_range[] */
#include <net/ip.h> /* for local_port_range[] */
#include <net/tcp.h> /* struct or_callable used in sock_rcv_skb */
#include <asm/uaccess.h>
#include <asm/ioctls.h>
Expand Down Expand Up @@ -3232,8 +3232,6 @@ static int selinux_socket_post_create(struct socket *sock, int family,
/* Range of port numbers used to automatically bind.
Need to determine whether we should perform a name_bind
permission check between the socket and the port number. */
#define ip_local_port_range_0 sysctl_local_port_range[0]
#define ip_local_port_range_1 sysctl_local_port_range[1]

static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen)
{
Expand Down Expand Up @@ -3276,20 +3274,27 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
addrp = (char *)&addr6->sin6_addr.s6_addr;
}

if (snum&&(snum < max(PROT_SOCK,ip_local_port_range_0) ||
snum > ip_local_port_range_1)) {
err = security_port_sid(sk->sk_family, sk->sk_type,
sk->sk_protocol, snum, &sid);
if (err)
goto out;
AVC_AUDIT_DATA_INIT(&ad,NET);
ad.u.net.sport = htons(snum);
ad.u.net.family = family;
err = avc_has_perm(isec->sid, sid,
isec->sclass,
SOCKET__NAME_BIND, &ad);
if (err)
goto out;
if (snum) {
int low, high;

inet_get_local_port_range(&low, &high);

if (snum < max(PROT_SOCK, low) || snum > high) {
err = security_port_sid(sk->sk_family,
sk->sk_type,
sk->sk_protocol, snum,
&sid);
if (err)
goto out;
AVC_AUDIT_DATA_INIT(&ad,NET);
ad.u.net.sport = htons(snum);
ad.u.net.family = family;
err = avc_has_perm(isec->sid, sid,
isec->sclass,
SOCKET__NAME_BIND, &ad);
if (err)
goto out;
}
}

switch(isec->sclass) {
Expand Down

0 comments on commit 3dfea98

Please sign in to comment.