Skip to content

Commit

Permalink
net ipv4: Convert ipv4.ip_local_port_range to be per netns v3
Browse files Browse the repository at this point in the history
- Move sysctl_local_ports from a global variable into struct netns_ipv4.
- Modify inet_get_local_port_range to take a struct net, and update all
  of the callers.
- Move the initialization of sysctl_local_ports into
   sysctl_net_ipv4.c:ipv4_sysctl_init_net from inet_connection_sock.c

v2:
- Ensure indentation used tabs
- Fixed ip.h so it applies cleanly to todays net-next

v3:
- Compile fixes of strange callers of inet_get_local_port_range.
  This patch now successfully passes an allmodconfig build.
  Removed manual inlining of inet_get_local_port_range in ipv4_local_port_range

Originally-by: Samya <[email protected]>
Acked-by: Nicolas Dichtel <[email protected]>
Signed-off-by: "Eric W. Biederman" <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
ebiederm authored and davem330 committed Oct 1, 2013
1 parent 56d7b53 commit 0bbf87d
Show file tree
Hide file tree
Showing 12 changed files with 56 additions and 46 deletions.
2 changes: 1 addition & 1 deletion drivers/infiniband/core/cma.c
Original file line number Diff line number Diff line change
Expand Up @@ -2294,7 +2294,7 @@ static int cma_alloc_any_port(struct idr *ps, struct rdma_id_private *id_priv)
int low, high, remaining;
unsigned int rover;

inet_get_local_port_range(&low, &high);
inet_get_local_port_range(&init_net, &low, &high);
remaining = (high - low) + 1;
rover = net_random() % remaining + low;
retry:
Expand Down
2 changes: 1 addition & 1 deletion drivers/net/vxlan.c
Original file line number Diff line number Diff line change
Expand Up @@ -2089,7 +2089,7 @@ static void vxlan_setup(struct net_device *dev)
vxlan->age_timer.function = vxlan_cleanup;
vxlan->age_timer.data = (unsigned long) vxlan;

inet_get_local_port_range(&low, &high);
inet_get_local_port_range(dev_net(dev), &low, &high);
vxlan->port_min = low;
vxlan->port_max = high;
vxlan->dst_port = htons(vxlan_port);
Expand Down
6 changes: 1 addition & 5 deletions include/net/ip.h
Original file line number Diff line number Diff line change
Expand Up @@ -217,11 +217,7 @@ static inline void snmp_mib_free(void __percpu *ptr[SNMP_ARRAY_SZ])
}
}

extern struct local_ports {
seqlock_t lock;
int range[2];
} sysctl_local_ports;
void inet_get_local_port_range(int *low, int *high);
void inet_get_local_port_range(struct net *net, int *low, int *high);

extern unsigned long *sysctl_local_reserved_ports;
static inline int inet_is_reserved_local_port(int port)
Expand Down
6 changes: 6 additions & 0 deletions include/net/netns/ipv4.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ struct fib_rules_ops;
struct hlist_head;
struct fib_table;
struct sock;
struct local_ports {
seqlock_t lock;
int range[2];
};

struct netns_ipv4 {
#ifdef CONFIG_SYSCTL
Expand Down Expand Up @@ -62,6 +66,8 @@ struct netns_ipv4 {
int sysctl_icmp_ratemask;
int sysctl_icmp_errors_use_inbound_ifaddr;

struct local_ports sysctl_local_ports;

int sysctl_tcp_ecn;

kgid_t sysctl_ping_group_range[2];
Expand Down
20 changes: 6 additions & 14 deletions net/ipv4/inet_connection_sock.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,27 +29,19 @@ const char inet_csk_timer_bug_msg[] = "inet_csk BUG: unknown timer value\n";
EXPORT_SYMBOL(inet_csk_timer_bug_msg);
#endif

/*
* This struct holds the first and last local port number.
*/
struct local_ports sysctl_local_ports __read_mostly = {
.lock = __SEQLOCK_UNLOCKED(sysctl_local_ports.lock),
.range = { 32768, 61000 },
};

unsigned long *sysctl_local_reserved_ports;
EXPORT_SYMBOL(sysctl_local_reserved_ports);

void inet_get_local_port_range(int *low, int *high)
void inet_get_local_port_range(struct net *net, int *low, int *high)
{
unsigned int seq;

do {
seq = read_seqbegin(&sysctl_local_ports.lock);
seq = read_seqbegin(&net->ipv4.sysctl_local_ports.lock);

*low = sysctl_local_ports.range[0];
*high = sysctl_local_ports.range[1];
} while (read_seqretry(&sysctl_local_ports.lock, seq));
*low = net->ipv4.sysctl_local_ports.range[0];
*high = net->ipv4.sysctl_local_ports.range[1];
} while (read_seqretry(&net->ipv4.sysctl_local_ports.lock, seq));
}
EXPORT_SYMBOL(inet_get_local_port_range);

Expand Down Expand Up @@ -116,7 +108,7 @@ int inet_csk_get_port(struct sock *sk, unsigned short snum)
int remaining, rover, low, high;

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

Expand Down
2 changes: 1 addition & 1 deletion net/ipv4/inet_hashtables.c
Original file line number Diff line number Diff line change
Expand Up @@ -494,7 +494,7 @@ int __inet_hash_connect(struct inet_timewait_death_row *death_row,
u32 offset = hint + port_offset;
struct inet_timewait_sock *tw = NULL;

inet_get_local_port_range(&low, &high);
inet_get_local_port_range(net, &low, &high);
remaining = (high - low) + 1;

local_bh_disable();
Expand Down
4 changes: 2 additions & 2 deletions net/ipv4/ping.c
Original file line number Diff line number Diff line change
Expand Up @@ -237,11 +237,11 @@ static void inet_get_ping_group_range_net(struct net *net, kgid_t *low,
unsigned int seq;

do {
seq = read_seqbegin(&sysctl_local_ports.lock);
seq = read_seqbegin(&net->ipv4.sysctl_local_ports.lock);

*low = data[0];
*high = data[1];
} while (read_seqretry(&sysctl_local_ports.lock, seq));
} while (read_seqretry(&net->ipv4.sysctl_local_ports.lock, seq));
}


Expand Down
52 changes: 34 additions & 18 deletions net/ipv4/sysctl_net_ipv4.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,19 +43,21 @@ static int ip_ping_group_range_min[] = { 0, 0 };
static int ip_ping_group_range_max[] = { GID_T_MAX, GID_T_MAX };

/* Update system visible IP port range */
static void set_local_port_range(int range[2])
static void set_local_port_range(struct net *net, int range[2])
{
write_seqlock(&sysctl_local_ports.lock);
sysctl_local_ports.range[0] = range[0];
sysctl_local_ports.range[1] = range[1];
write_sequnlock(&sysctl_local_ports.lock);
write_seqlock(&net->ipv4.sysctl_local_ports.lock);
net->ipv4.sysctl_local_ports.range[0] = range[0];
net->ipv4.sysctl_local_ports.range[1] = range[1];
write_sequnlock(&net->ipv4.sysctl_local_ports.lock);
}

/* Validate changes from /proc interface. */
static int ipv4_local_port_range(struct ctl_table *table, int write,
void __user *buffer,
size_t *lenp, loff_t *ppos)
{
struct net *net =
container_of(table->data, struct net, ipv4.sysctl_local_ports.range);
int ret;
int range[2];
struct ctl_table tmp = {
Expand All @@ -66,14 +68,15 @@ static int ipv4_local_port_range(struct ctl_table *table, int write,
.extra2 = &ip_local_port_range_max,
};

inet_get_local_port_range(range, range + 1);
inet_get_local_port_range(net, &range[0], &range[1]);

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

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

return ret;
Expand All @@ -83,23 +86,27 @@ static int ipv4_local_port_range(struct ctl_table *table, int write,
static void inet_get_ping_group_range_table(struct ctl_table *table, kgid_t *low, kgid_t *high)
{
kgid_t *data = table->data;
struct net *net =
container_of(table->data, struct net, ipv4.sysctl_ping_group_range);
unsigned int seq;
do {
seq = read_seqbegin(&sysctl_local_ports.lock);
seq = read_seqbegin(&net->ipv4.sysctl_local_ports.lock);

*low = data[0];
*high = data[1];
} while (read_seqretry(&sysctl_local_ports.lock, seq));
} while (read_seqretry(&net->ipv4.sysctl_local_ports.lock, seq));
}

/* Update system visible IP port range */
static void set_ping_group_range(struct ctl_table *table, kgid_t low, kgid_t high)
{
kgid_t *data = table->data;
write_seqlock(&sysctl_local_ports.lock);
struct net *net =
container_of(table->data, struct net, ipv4.sysctl_ping_group_range);
write_seqlock(&net->ipv4.sysctl_local_ports.lock);
data[0] = low;
data[1] = high;
write_sequnlock(&sysctl_local_ports.lock);
write_sequnlock(&net->ipv4.sysctl_local_ports.lock);
}

/* Validate changes from /proc interface. */
Expand Down Expand Up @@ -474,13 +481,6 @@ static struct ctl_table ipv4_table[] = {
.mode = 0644,
.proc_handler = proc_dointvec
},
{
.procname = "ip_local_port_range",
.data = &sysctl_local_ports.range,
.maxlen = sizeof(sysctl_local_ports.range),
.mode = 0644,
.proc_handler = ipv4_local_port_range,
},
{
.procname = "ip_local_reserved_ports",
.data = NULL, /* initialized in sysctl_ipv4_init */
Expand Down Expand Up @@ -853,6 +853,13 @@ static struct ctl_table ipv4_net_table[] = {
.mode = 0644,
.proc_handler = proc_dointvec
},
{
.procname = "ip_local_port_range",
.maxlen = sizeof(init_net.ipv4.sysctl_local_ports.range),
.data = &init_net.ipv4.sysctl_local_ports.range,
.mode = 0644,
.proc_handler = ipv4_local_port_range,
},
{
.procname = "tcp_mem",
.maxlen = sizeof(init_net.ipv4.sysctl_tcp_mem),
Expand Down Expand Up @@ -888,6 +895,8 @@ static __net_init int ipv4_sysctl_init_net(struct net *net)
&net->ipv4.sysctl_ping_group_range;
table[7].data =
&net->ipv4.sysctl_tcp_ecn;
table[8].data =
&net->ipv4.sysctl_local_ports.range;

/* Don't export sysctls to unprivileged users */
if (net->user_ns != &init_user_ns)
Expand All @@ -901,6 +910,13 @@ static __net_init int ipv4_sysctl_init_net(struct net *net)
net->ipv4.sysctl_ping_group_range[0] = make_kgid(&init_user_ns, 1);
net->ipv4.sysctl_ping_group_range[1] = make_kgid(&init_user_ns, 0);

/*
* Set defaults for local port range
*/
seqlock_init(&net->ipv4.sysctl_local_ports.lock);
net->ipv4.sysctl_local_ports.range[0] = 32768;
net->ipv4.sysctl_local_ports.range[1] = 61000;

tcp_init_mem(net);

net->ipv4.ipv4_hdr = register_net_sysctl(net, "net/ipv4", table);
Expand Down
2 changes: 1 addition & 1 deletion net/ipv4/udp.c
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ int udp_lib_get_port(struct sock *sk, unsigned short snum,
unsigned short first, last;
DECLARE_BITMAP(bitmap, PORTS_PER_CHAIN);

inet_get_local_port_range(&low, &high);
inet_get_local_port_range(net, &low, &high);
remaining = (high - low) + 1;

rand = net_random();
Expand Down
2 changes: 1 addition & 1 deletion net/openvswitch/vport-vxlan.c
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ static int vxlan_tnl_send(struct vport *vport, struct sk_buff *skb)

skb->local_df = 1;

inet_get_local_port_range(&port_min, &port_max);
inet_get_local_port_range(net, &port_min, &port_max);
src_port = vxlan_src_port(port_min, port_max, skb);

err = vxlan_xmit_skb(vxlan_port->vs, rt, skb,
Expand Down
2 changes: 1 addition & 1 deletion net/sctp/socket.c
Original file line number Diff line number Diff line change
Expand Up @@ -5890,7 +5890,7 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
int low, high, remaining, index;
unsigned int rover;

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

Expand Down
2 changes: 1 addition & 1 deletion security/selinux/hooks.c
Original file line number Diff line number Diff line change
Expand Up @@ -3929,7 +3929,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
if (snum) {
int low, high;

inet_get_local_port_range(&low, &high);
inet_get_local_port_range(sock_net(sk), &low, &high);

if (snum < max(PROT_SOCK, low) || snum > high) {
err = sel_netport_sid(sk->sk_protocol,
Expand Down

0 comments on commit 0bbf87d

Please sign in to comment.