summaryrefslogtreecommitdiffstats
path: root/net/ipv4
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4')
-rw-r--r--net/ipv4/cipso_ipv4.c7
-rw-r--r--net/ipv4/ip_options.c2
-rw-r--r--net/ipv4/ipconfig.c2
-rw-r--r--net/ipv4/ipvs/ip_vs_ftp.c2
-rw-r--r--net/ipv4/ipvs/ip_vs_proto_tcp.c2
-rw-r--r--net/ipv4/ipvs/ip_vs_proto_udp.c8
-rw-r--r--net/ipv4/netfilter/arp_tables.c25
-rw-r--r--net/ipv4/netfilter/ip_queue.c7
-rw-r--r--net/ipv4/netfilter/ip_tables.c67
-rw-r--r--net/ipv4/raw.c17
-rw-r--r--net/ipv4/sysctl_net_ipv4.c7
-rw-r--r--net/ipv4/tcp.c11
-rw-r--r--net/ipv4/tcp_cong.c8
-rw-r--r--net/ipv4/tcp_cubic.c6
-rw-r--r--net/ipv4/tcp_htcp.c2
15 files changed, 94 insertions, 79 deletions
diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c
index e2077a3aa8c..6460233407c 100644
--- a/net/ipv4/cipso_ipv4.c
+++ b/net/ipv4/cipso_ipv4.c
@@ -1307,7 +1307,8 @@ int cipso_v4_socket_setattr(const struct socket *sock,
/* We can't use ip_options_get() directly because it makes a call to
* ip_options_get_alloc() which allocates memory with GFP_KERNEL and
- * we can't block here. */
+ * we won't always have CAP_NET_RAW even though we _always_ want to
+ * set the IPOPT_CIPSO option. */
opt_len = (buf_len + 3) & ~3;
opt = kzalloc(sizeof(*opt) + opt_len, GFP_ATOMIC);
if (opt == NULL) {
@@ -1317,11 +1318,9 @@ int cipso_v4_socket_setattr(const struct socket *sock,
memcpy(opt->__data, buf, buf_len);
opt->optlen = opt_len;
opt->is_data = 1;
+ opt->cipso = sizeof(struct iphdr);
kfree(buf);
buf = NULL;
- ret_val = ip_options_compile(opt, NULL);
- if (ret_val != 0)
- goto socket_setattr_failure;
sk_inet = inet_sk(sk);
if (sk_inet->is_icsk) {
diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c
index 8dabbfc3126..9f02917d6f4 100644
--- a/net/ipv4/ip_options.c
+++ b/net/ipv4/ip_options.c
@@ -443,7 +443,7 @@ int ip_options_compile(struct ip_options * opt, struct sk_buff * skb)
opt->router_alert = optptr - iph;
break;
case IPOPT_CIPSO:
- if (opt->cipso) {
+ if ((!skb && !capable(CAP_NET_RAW)) || opt->cipso) {
pp_ptr = optptr;
goto error;
}
diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c
index f8ce8475915..955a07abb91 100644
--- a/net/ipv4/ipconfig.c
+++ b/net/ipv4/ipconfig.c
@@ -420,7 +420,7 @@ ic_rarp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt
{
struct arphdr *rarp;
unsigned char *rarp_ptr;
- unsigned long sip, tip;
+ u32 sip, tip;
unsigned char *sha, *tha; /* s for "source", t for "target" */
struct ic_device *d;
diff --git a/net/ipv4/ipvs/ip_vs_ftp.c b/net/ipv4/ipvs/ip_vs_ftp.c
index 6d398f10aa9..687c1de1146 100644
--- a/net/ipv4/ipvs/ip_vs_ftp.c
+++ b/net/ipv4/ipvs/ip_vs_ftp.c
@@ -200,7 +200,7 @@ static int ip_vs_ftp_out(struct ip_vs_app *app, struct ip_vs_conn *cp,
from = n_cp->vaddr;
port = n_cp->vport;
sprintf(buf,"%d,%d,%d,%d,%d,%d", NIPQUAD(from),
- ntohs(port)&255, (ntohs(port)>>8)&255);
+ (ntohs(port)>>8)&255, ntohs(port)&255);
buf_len = strlen(buf);
/*
diff --git a/net/ipv4/ipvs/ip_vs_proto_tcp.c b/net/ipv4/ipvs/ip_vs_proto_tcp.c
index bfe779e7459..6ff05c3a32e 100644
--- a/net/ipv4/ipvs/ip_vs_proto_tcp.c
+++ b/net/ipv4/ipvs/ip_vs_proto_tcp.c
@@ -117,7 +117,7 @@ tcp_fast_csum_update(struct tcphdr *tcph, __be32 oldip, __be32 newip,
{
tcph->check =
ip_vs_check_diff(~oldip, newip,
- ip_vs_check_diff(oldport ^ htonl(0xFFFF),
+ ip_vs_check_diff(oldport ^ htons(0xFFFF),
newport, tcph->check));
}
diff --git a/net/ipv4/ipvs/ip_vs_proto_udp.c b/net/ipv4/ipvs/ip_vs_proto_udp.c
index 54aa7603591..691c8b637b2 100644
--- a/net/ipv4/ipvs/ip_vs_proto_udp.c
+++ b/net/ipv4/ipvs/ip_vs_proto_udp.c
@@ -122,10 +122,10 @@ udp_fast_csum_update(struct udphdr *uhdr, __be32 oldip, __be32 newip,
{
uhdr->check =
ip_vs_check_diff(~oldip, newip,
- ip_vs_check_diff(oldport ^ htonl(0xFFFF),
+ ip_vs_check_diff(oldport ^ htons(0xFFFF),
newport, uhdr->check));
if (!uhdr->check)
- uhdr->check = htonl(0xFFFF);
+ uhdr->check = -1;
}
static int
@@ -173,7 +173,7 @@ udp_snat_handler(struct sk_buff **pskb,
cp->protocol,
(*pskb)->csum);
if (udph->check == 0)
- udph->check = htonl(0xFFFF);
+ udph->check = -1;
IP_VS_DBG(11, "O-pkt: %s O-csum=%d (+%zd)\n",
pp->name, udph->check,
(char*)&(udph->check) - (char*)udph);
@@ -228,7 +228,7 @@ udp_dnat_handler(struct sk_buff **pskb,
cp->protocol,
(*pskb)->csum);
if (udph->check == 0)
- udph->check = 0xFFFF;
+ udph->check = -1;
(*pskb)->ip_summed = CHECKSUM_UNNECESSARY;
}
return 1;
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
index 0849f1cced1..413c2d0a1f3 100644
--- a/net/ipv4/netfilter/arp_tables.c
+++ b/net/ipv4/netfilter/arp_tables.c
@@ -466,7 +466,13 @@ static inline int check_entry(struct arpt_entry *e, const char *name, unsigned i
return -EINVAL;
}
+ if (e->target_offset + sizeof(struct arpt_entry_target) > e->next_offset)
+ return -EINVAL;
+
t = arpt_get_target(e);
+ if (e->target_offset + t->u.target_size > e->next_offset)
+ return -EINVAL;
+
target = try_then_request_module(xt_find_target(NF_ARP, t->u.user.name,
t->u.user.revision),
"arpt_%s", t->u.user.name);
@@ -621,20 +627,18 @@ static int translate_table(const char *name,
}
}
- if (!mark_source_chains(newinfo, valid_hooks, entry0)) {
- duprintf("Looping hook\n");
- return -ELOOP;
- }
-
/* Finally, each sanity check must pass */
i = 0;
ret = ARPT_ENTRY_ITERATE(entry0, newinfo->size,
check_entry, name, size, &i);
- if (ret != 0) {
- ARPT_ENTRY_ITERATE(entry0, newinfo->size,
- cleanup_entry, &i);
- return ret;
+ if (ret != 0)
+ goto cleanup;
+
+ ret = -ELOOP;
+ if (!mark_source_chains(newinfo, valid_hooks, entry0)) {
+ duprintf("Looping hook\n");
+ goto cleanup;
}
/* And one copy for every other CPU */
@@ -643,6 +647,9 @@ static int translate_table(const char *name,
memcpy(newinfo->entries[i], entry0, newinfo->size);
}
+ return 0;
+cleanup:
+ ARPT_ENTRY_ITERATE(entry0, newinfo->size, cleanup_entry, &i);
return ret;
}
diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c
index 7edad790478..97556cc2e4e 100644
--- a/net/ipv4/netfilter/ip_queue.c
+++ b/net/ipv4/netfilter/ip_queue.c
@@ -351,9 +351,10 @@ ipq_mangle_ipv4(ipq_verdict_msg_t *v, struct ipq_queue_entry *e)
if (v->data_len < sizeof(*user_iph))
return 0;
diff = v->data_len - e->skb->len;
- if (diff < 0)
- skb_trim(e->skb, v->data_len);
- else if (diff > 0) {
+ if (diff < 0) {
+ if (pskb_trim(e->skb, v->data_len))
+ return -ENOMEM;
+ } else if (diff > 0) {
if (v->data_len > 0xFFFF)
return -EINVAL;
if (diff > skb_tailroom(e->skb)) {
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index 4b90927619b..8a455439b12 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -547,12 +547,18 @@ check_entry(struct ipt_entry *e, const char *name, unsigned int size,
return -EINVAL;
}
+ if (e->target_offset + sizeof(struct ipt_entry_target) > e->next_offset)
+ return -EINVAL;
+
j = 0;
ret = IPT_MATCH_ITERATE(e, check_match, name, &e->ip, e->comefrom, &j);
if (ret != 0)
goto cleanup_matches;
t = ipt_get_target(e);
+ ret = -EINVAL;
+ if (e->target_offset + t->u.target_size > e->next_offset)
+ goto cleanup_matches;
target = try_then_request_module(xt_find_target(AF_INET,
t->u.user.name,
t->u.user.revision),
@@ -712,19 +718,17 @@ translate_table(const char *name,
}
}
- if (!mark_source_chains(newinfo, valid_hooks, entry0))
- return -ELOOP;
-
/* Finally, each sanity check must pass */
i = 0;
ret = IPT_ENTRY_ITERATE(entry0, newinfo->size,
check_entry, name, size, &i);
- if (ret != 0) {
- IPT_ENTRY_ITERATE(entry0, newinfo->size,
- cleanup_entry, &i);
- return ret;
- }
+ if (ret != 0)
+ goto cleanup;
+
+ ret = -ELOOP;
+ if (!mark_source_chains(newinfo, valid_hooks, entry0))
+ goto cleanup;
/* And one copy for every other CPU */
for_each_possible_cpu(i) {
@@ -732,6 +736,9 @@ translate_table(const char *name,
memcpy(newinfo->entries[i], entry0, newinfo->size);
}
+ return 0;
+cleanup:
+ IPT_ENTRY_ITERATE(entry0, newinfo->size, cleanup_entry, &i);
return ret;
}
@@ -1463,6 +1470,10 @@ check_compat_entry_size_and_hooks(struct ipt_entry *e,
return -EINVAL;
}
+ if (e->target_offset + sizeof(struct compat_xt_entry_target) >
+ e->next_offset)
+ return -EINVAL;
+
off = 0;
entry_offset = (void *)e - (void *)base;
j = 0;
@@ -1472,6 +1483,9 @@ check_compat_entry_size_and_hooks(struct ipt_entry *e,
goto cleanup_matches;
t = ipt_get_target(e);
+ ret = -EINVAL;
+ if (e->target_offset + t->u.target_size > e->next_offset)
+ goto cleanup_matches;
target = try_then_request_module(xt_find_target(AF_INET,
t->u.user.name,
t->u.user.revision),
@@ -1513,7 +1527,7 @@ cleanup_matches:
static inline int compat_copy_match_from_user(struct ipt_entry_match *m,
void **dstptr, compat_uint_t *size, const char *name,
- const struct ipt_ip *ip, unsigned int hookmask, int *i)
+ const struct ipt_ip *ip, unsigned int hookmask)
{
struct ipt_entry_match *dm;
struct ipt_match *match;
@@ -1526,22 +1540,13 @@ static inline int compat_copy_match_from_user(struct ipt_entry_match *m,
ret = xt_check_match(match, AF_INET, dm->u.match_size - sizeof(*dm),
name, hookmask, ip->proto,
ip->invflags & IPT_INV_PROTO);
- if (ret)
- goto err;
-
- if (m->u.kernel.match->checkentry
+ if (!ret && m->u.kernel.match->checkentry
&& !m->u.kernel.match->checkentry(name, ip, match, dm->data,
hookmask)) {
duprintf("ip_tables: check failed for `%s'.\n",
m->u.kernel.match->name);
ret = -EINVAL;
- goto err;
}
- (*i)++;
- return 0;
-
-err:
- module_put(m->u.kernel.match->me);
return ret;
}
@@ -1553,19 +1558,18 @@ static int compat_copy_entry_from_user(struct ipt_entry *e, void **dstptr,
struct ipt_target *target;
struct ipt_entry *de;
unsigned int origsize;
- int ret, h, j;
+ int ret, h;
ret = 0;
origsize = *size;
de = (struct ipt_entry *)*dstptr;
memcpy(de, e, sizeof(struct ipt_entry));
- j = 0;
*dstptr += sizeof(struct compat_ipt_entry);
ret = IPT_MATCH_ITERATE(e, compat_copy_match_from_user, dstptr, size,
- name, &de->ip, de->comefrom, &j);
+ name, &de->ip, de->comefrom);
if (ret)
- goto cleanup_matches;
+ goto err;
de->target_offset = e->target_offset - (origsize - *size);
t = ipt_get_target(e);
target = t->u.kernel.target;
@@ -1599,12 +1603,7 @@ static int compat_copy_entry_from_user(struct ipt_entry *e, void **dstptr,
goto err;
}
ret = 0;
- return ret;
-
err:
- module_put(t->u.kernel.target->me);
-cleanup_matches:
- IPT_MATCH_ITERATE(e, cleanup_match, &j);
return ret;
}
@@ -1618,7 +1617,7 @@ translate_compat_table(const char *name,
unsigned int *hook_entries,
unsigned int *underflows)
{
- unsigned int i;
+ unsigned int i, j;
struct xt_table_info *newinfo, *info;
void *pos, *entry0, *entry1;
unsigned int size;
@@ -1636,21 +1635,21 @@ translate_compat_table(const char *name,
}
duprintf("translate_compat_table: size %u\n", info->size);
- i = 0;
+ j = 0;
xt_compat_lock(AF_INET);
/* Walk through entries, checking offsets. */
ret = IPT_ENTRY_ITERATE(entry0, total_size,
check_compat_entry_size_and_hooks,
info, &size, entry0,
entry0 + total_size,
- hook_entries, underflows, &i, name);
+ hook_entries, underflows, &j, name);
if (ret != 0)
goto out_unlock;
ret = -EINVAL;
- if (i != number) {
+ if (j != number) {
duprintf("translate_compat_table: %u not %u entries\n",
- i, number);
+ j, number);
goto out_unlock;
}
@@ -1709,8 +1708,10 @@ translate_compat_table(const char *name,
free_newinfo:
xt_free_table_info(newinfo);
out:
+ IPT_ENTRY_ITERATE(entry0, total_size, cleanup_entry, &j);
return ret;
out_unlock:
+ compat_flush_offsets();
xt_compat_unlock(AF_INET);
goto out;
}
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
index b430cf2a4f6..5c31dead2bd 100644
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -329,7 +329,7 @@ error:
return err;
}
-static void raw_probe_proto_opt(struct flowi *fl, struct msghdr *msg)
+static int raw_probe_proto_opt(struct flowi *fl, struct msghdr *msg)
{
struct iovec *iov;
u8 __user *type = NULL;
@@ -338,7 +338,7 @@ static void raw_probe_proto_opt(struct flowi *fl, struct msghdr *msg)
unsigned int i;
if (!msg->msg_iov)
- return;
+ return 0;
for (i = 0; i < msg->msg_iovlen; i++) {
iov = &msg->msg_iov[i];
@@ -360,8 +360,9 @@ static void raw_probe_proto_opt(struct flowi *fl, struct msghdr *msg)
code = iov->iov_base;
if (type && code) {
- get_user(fl->fl_icmp_type, type);
- get_user(fl->fl_icmp_code, code);
+ if (get_user(fl->fl_icmp_type, type) ||
+ get_user(fl->fl_icmp_code, code))
+ return -EFAULT;
probed = 1;
}
break;
@@ -372,6 +373,7 @@ static void raw_probe_proto_opt(struct flowi *fl, struct msghdr *msg)
if (probed)
break;
}
+ return 0;
}
static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
@@ -480,8 +482,11 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
.proto = inet->hdrincl ? IPPROTO_RAW :
sk->sk_protocol,
};
- if (!inet->hdrincl)
- raw_probe_proto_opt(&fl, msg);
+ if (!inet->hdrincl) {
+ err = raw_probe_proto_opt(&fl, msg);
+ if (err)
+ goto done;
+ }
security_sk_classify_flow(sk, &fl);
err = ip_route_output_flow(&rt, &fl, sk, !(msg->msg_flags&MSG_DONTWAIT));
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index e82a5be894b..15061b31441 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -129,13 +129,6 @@ static int sysctl_tcp_congestion_control(ctl_table *table, int __user *name,
return ret;
}
-static int __init tcp_congestion_default(void)
-{
- return tcp_set_default_congestion_control(CONFIG_DEFAULT_TCP_CONG);
-}
-
-late_initcall(tcp_congestion_default);
-
ctl_table ipv4_table[] = {
{
.ctl_name = NET_IPV4_TCP_TIMESTAMPS,
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 66e9a729f6d..c05e8edaf54 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -2270,7 +2270,7 @@ void __init tcp_init(void)
thash_entries,
(num_physpages >= 128 * 1024) ?
13 : 15,
- HASH_HIGHMEM,
+ 0,
&tcp_hashinfo.ehash_size,
NULL,
0);
@@ -2286,7 +2286,7 @@ void __init tcp_init(void)
tcp_hashinfo.ehash_size,
(num_physpages >= 128 * 1024) ?
13 : 15,
- HASH_HIGHMEM,
+ 0,
&tcp_hashinfo.bhash_size,
NULL,
64 * 1024);
@@ -2316,9 +2316,10 @@ void __init tcp_init(void)
sysctl_max_syn_backlog = 128;
}
- sysctl_tcp_mem[0] = 768 << order;
- sysctl_tcp_mem[1] = 1024 << order;
- sysctl_tcp_mem[2] = 1536 << order;
+ /* Allow no more than 3/4 kernel memory (usually less) allocated to TCP */
+ sysctl_tcp_mem[0] = (1536 / sizeof (struct inet_bind_hashbucket)) << order;
+ sysctl_tcp_mem[1] = sysctl_tcp_mem[0] * 4 / 3;
+ sysctl_tcp_mem[2] = sysctl_tcp_mem[0] * 2;
limit = ((unsigned long)sysctl_tcp_mem[1]) << (PAGE_SHIFT - 7);
max_share = min(4UL*1024*1024, limit);
diff --git a/net/ipv4/tcp_cong.c b/net/ipv4/tcp_cong.c
index af0aca1e6be..1e2982f4acd 100644
--- a/net/ipv4/tcp_cong.c
+++ b/net/ipv4/tcp_cong.c
@@ -131,6 +131,14 @@ int tcp_set_default_congestion_control(const char *name)
return ret;
}
+/* Set default value from kernel configuration at bootup */
+static int __init tcp_congestion_default(void)
+{
+ return tcp_set_default_congestion_control(CONFIG_DEFAULT_TCP_CONG);
+}
+late_initcall(tcp_congestion_default);
+
+
/* Get current default congestion control */
void tcp_get_default_congestion_control(char *name)
{
diff --git a/net/ipv4/tcp_cubic.c b/net/ipv4/tcp_cubic.c
index a60ef38d75c..6ad18480226 100644
--- a/net/ipv4/tcp_cubic.c
+++ b/net/ipv4/tcp_cubic.c
@@ -190,7 +190,7 @@ static inline void bictcp_update(struct bictcp *ca, u32 cwnd)
*/
/* change the unit from HZ to bictcp_HZ */
- t = ((tcp_time_stamp + ca->delay_min - ca->epoch_start)
+ t = ((tcp_time_stamp + (ca->delay_min>>3) - ca->epoch_start)
<< BICTCP_HZ) / HZ;
if (t < ca->bic_K) /* t - K */
@@ -259,7 +259,7 @@ static inline void measure_delay(struct sock *sk)
(s32)(tcp_time_stamp - ca->epoch_start) < HZ)
return;
- delay = tcp_time_stamp - tp->rx_opt.rcv_tsecr;
+ delay = (tcp_time_stamp - tp->rx_opt.rcv_tsecr)<<3;
if (delay == 0)
delay = 1;
@@ -366,7 +366,7 @@ static int __init cubictcp_register(void)
beta_scale = 8*(BICTCP_BETA_SCALE+beta)/ 3 / (BICTCP_BETA_SCALE - beta);
- cube_rtt_scale = (bic_scale << 3) / 10; /* 1024*c/rtt */
+ cube_rtt_scale = (bic_scale * 10); /* 1024*c/rtt */
/* calculate the "K" for (wmax-cwnd) = c/rtt * K^3
* so K = cubic_root( (wmax-cwnd)*rtt/c )
diff --git a/net/ipv4/tcp_htcp.c b/net/ipv4/tcp_htcp.c
index 682e7d5b6f2..283be3cb466 100644
--- a/net/ipv4/tcp_htcp.c
+++ b/net/ipv4/tcp_htcp.c
@@ -23,7 +23,7 @@ module_param(use_bandwidth_switch, int, 0644);
MODULE_PARM_DESC(use_bandwidth_switch, "turn on/off bandwidth switcher");
struct htcp {
- u16 alpha; /* Fixed point arith, << 7 */
+ u32 alpha; /* Fixed point arith, << 7 */
u8 beta; /* Fixed point arith, << 7 */
u8 modeswitch; /* Delay modeswitch until we had at least one congestion event */
u32 last_cong; /* Time since last congestion event end */