import PULS_20180308
This commit is contained in:
+3
-1
@@ -711,11 +711,13 @@ static int ethtool_reset(struct net_device *dev, char __user *useraddr)
|
||||
|
||||
static int ethtool_get_wol(struct net_device *dev, char __user *useraddr)
|
||||
{
|
||||
struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL };
|
||||
struct ethtool_wolinfo wol;
|
||||
|
||||
if (!dev->ethtool_ops->get_wol)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
memset(&wol, 0, sizeof(struct ethtool_wolinfo));
|
||||
wol.cmd = ETHTOOL_GWOL;
|
||||
dev->ethtool_ops->get_wol(dev, &wol);
|
||||
|
||||
if (copy_to_user(useraddr, &wol, sizeof(wol)))
|
||||
|
||||
+2
-2
@@ -731,7 +731,7 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
|
||||
val = min_t(u32, val, sysctl_wmem_max);
|
||||
set_sndbuf:
|
||||
sk->sk_userlocks |= SOCK_SNDBUF_LOCK;
|
||||
sk->sk_sndbuf = max_t(u32, val * 2, SOCK_MIN_SNDBUF);
|
||||
sk->sk_sndbuf = max_t(int, val * 2, SOCK_MIN_SNDBUF);
|
||||
/* Wake up sending tasks if we upped the value. */
|
||||
sk->sk_write_space(sk);
|
||||
break;
|
||||
@@ -767,7 +767,7 @@ set_rcvbuf:
|
||||
* returning the value we actually used in getsockopt
|
||||
* is the most desirable behavior.
|
||||
*/
|
||||
sk->sk_rcvbuf = max_t(u32, val * 2, SOCK_MIN_RCVBUF);
|
||||
sk->sk_rcvbuf = max_t(int, val * 2, SOCK_MIN_RCVBUF);
|
||||
break;
|
||||
|
||||
case SO_RCVBUFFORCE:
|
||||
|
||||
+2
-1
@@ -606,7 +606,8 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
|
||||
if (inet_csk(sk)->icsk_af_ops->conn_request(sk,
|
||||
skb) < 0)
|
||||
return 1;
|
||||
goto discard;
|
||||
consume_skb(skb);
|
||||
return 0;
|
||||
}
|
||||
if (dh->dccph_type == DCCP_PKT_RESET)
|
||||
goto discard;
|
||||
|
||||
@@ -1046,6 +1046,13 @@ void ipv4_pktinfo_prepare(struct sk_buff *skb)
|
||||
pktinfo->ipi_ifindex = 0;
|
||||
pktinfo->ipi_spec_dst.s_addr = 0;
|
||||
}
|
||||
/* We need to keep the dst for __ip_options_echo()
|
||||
* We could restrict the test to opt.ts_needtime || opt.srr,
|
||||
* but the following is good enough as IP options are not often used.
|
||||
*/
|
||||
if (unlikely(IPCB(skb)->opt.optlen))
|
||||
skb_dst_force(skb);
|
||||
else
|
||||
skb_dst_drop(skb);
|
||||
}
|
||||
|
||||
|
||||
@@ -350,11 +350,12 @@ unsigned int arpt_do_table(struct sk_buff *skb,
|
||||
}
|
||||
|
||||
/* All zeroes == unconditional rule. */
|
||||
static inline bool unconditional(const struct arpt_arp *arp)
|
||||
static inline bool unconditional(const struct arpt_entry *e)
|
||||
{
|
||||
static const struct arpt_arp uncond;
|
||||
|
||||
return memcmp(arp, &uncond, sizeof(uncond)) == 0;
|
||||
return e->target_offset == sizeof(struct arpt_entry) &&
|
||||
memcmp(&e->arp, &uncond, sizeof(uncond)) == 0;
|
||||
}
|
||||
|
||||
/* Figures out from what hook each rule can be called: returns 0 if
|
||||
@@ -393,11 +394,10 @@ static int mark_source_chains(const struct xt_table_info *newinfo,
|
||||
|= ((1 << hook) | (1 << NF_ARP_NUMHOOKS));
|
||||
|
||||
/* Unconditional return/END. */
|
||||
if ((e->target_offset == sizeof(struct arpt_entry) &&
|
||||
if ((unconditional(e) &&
|
||||
(strcmp(t->target.u.user.name,
|
||||
XT_STANDARD_TARGET) == 0) &&
|
||||
t->verdict < 0 && unconditional(&e->arp)) ||
|
||||
visited) {
|
||||
t->verdict < 0) || visited) {
|
||||
unsigned int oldpos, size;
|
||||
|
||||
if ((strcmp(t->target.u.user.name,
|
||||
@@ -465,14 +465,12 @@ static int mark_source_chains(const struct xt_table_info *newinfo,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline int check_entry(const struct arpt_entry *e, const char *name)
|
||||
static inline int check_entry(const struct arpt_entry *e)
|
||||
{
|
||||
const struct xt_entry_target *t;
|
||||
|
||||
if (!arp_checkentry(&e->arp)) {
|
||||
duprintf("arp_tables: arp check failed %p %s.\n", e, name);
|
||||
if (!arp_checkentry(&e->arp))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (e->target_offset + sizeof(struct xt_entry_target) > e->next_offset)
|
||||
return -EINVAL;
|
||||
@@ -484,6 +482,7 @@ static inline int check_entry(const struct arpt_entry *e, const char *name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static inline int check_target(struct arpt_entry *e, const char *name)
|
||||
{
|
||||
struct xt_entry_target *t = arpt_get_target(e);
|
||||
@@ -513,10 +512,6 @@ find_check_entry(struct arpt_entry *e, const char *name, unsigned int size)
|
||||
struct xt_target *target;
|
||||
int ret;
|
||||
|
||||
ret = check_entry(e, name);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
t = arpt_get_target(e);
|
||||
target = xt_request_find_target(NFPROTO_ARP, t->u.user.name,
|
||||
t->u.user.revision);
|
||||
@@ -542,7 +537,7 @@ static bool check_underflow(const struct arpt_entry *e)
|
||||
const struct xt_entry_target *t;
|
||||
unsigned int verdict;
|
||||
|
||||
if (!unconditional(&e->arp))
|
||||
if (!unconditional(e))
|
||||
return false;
|
||||
t = arpt_get_target_c(e);
|
||||
if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0)
|
||||
@@ -561,9 +556,11 @@ static inline int check_entry_size_and_hooks(struct arpt_entry *e,
|
||||
unsigned int valid_hooks)
|
||||
{
|
||||
unsigned int h;
|
||||
int err;
|
||||
|
||||
if ((unsigned long)e % __alignof__(struct arpt_entry) != 0 ||
|
||||
(unsigned char *)e + sizeof(struct arpt_entry) >= limit) {
|
||||
(unsigned char *)e + sizeof(struct arpt_entry) >= limit ||
|
||||
(unsigned char *)e + e->next_offset > limit) {
|
||||
duprintf("Bad offset %p\n", e);
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -575,6 +572,10 @@ static inline int check_entry_size_and_hooks(struct arpt_entry *e,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = check_entry(e);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Check hooks & underflows */
|
||||
for (h = 0; h < NF_ARP_NUMHOOKS; h++) {
|
||||
if (!(valid_hooks & (1 << h)))
|
||||
@@ -1219,7 +1220,8 @@ check_compat_entry_size_and_hooks(struct compat_arpt_entry *e,
|
||||
|
||||
duprintf("check_compat_entry_size_and_hooks %p\n", e);
|
||||
if ((unsigned long)e % __alignof__(struct compat_arpt_entry) != 0 ||
|
||||
(unsigned char *)e + sizeof(struct compat_arpt_entry) >= limit) {
|
||||
(unsigned char *)e + sizeof(struct compat_arpt_entry) >= limit ||
|
||||
(unsigned char *)e + e->next_offset > limit) {
|
||||
duprintf("Bad offset %p, limit = %p\n", e, limit);
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -1232,7 +1234,7 @@ check_compat_entry_size_and_hooks(struct compat_arpt_entry *e,
|
||||
}
|
||||
|
||||
/* For purposes of check_entry casting the compat entry is fine */
|
||||
ret = check_entry((struct arpt_entry *)e, name);
|
||||
ret = check_entry((struct arpt_entry *)e);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
||||
@@ -168,11 +168,12 @@ get_entry(const void *base, unsigned int offset)
|
||||
|
||||
/* All zeroes == unconditional rule. */
|
||||
/* Mildly perf critical (only if packet tracing is on) */
|
||||
static inline bool unconditional(const struct ipt_ip *ip)
|
||||
static inline bool unconditional(const struct ipt_entry *e)
|
||||
{
|
||||
static const struct ipt_ip uncond;
|
||||
|
||||
return memcmp(ip, &uncond, sizeof(uncond)) == 0;
|
||||
return e->target_offset == sizeof(struct ipt_entry) &&
|
||||
memcmp(&e->ip, &uncond, sizeof(uncond)) == 0;
|
||||
#undef FWINV
|
||||
}
|
||||
|
||||
@@ -229,11 +230,10 @@ get_chainname_rulenum(const struct ipt_entry *s, const struct ipt_entry *e,
|
||||
} else if (s == e) {
|
||||
(*rulenum)++;
|
||||
|
||||
if (s->target_offset == sizeof(struct ipt_entry) &&
|
||||
if (unconditional(s) &&
|
||||
strcmp(t->target.u.kernel.target->name,
|
||||
XT_STANDARD_TARGET) == 0 &&
|
||||
t->verdict < 0 &&
|
||||
unconditional(&s->ip)) {
|
||||
t->verdict < 0) {
|
||||
/* Tail of chains: STANDARD target (return/policy) */
|
||||
*comment = *chainname == hookname
|
||||
? comments[NF_IP_TRACE_COMMENT_POLICY]
|
||||
@@ -467,11 +467,10 @@ mark_source_chains(const struct xt_table_info *newinfo,
|
||||
e->comefrom |= ((1 << hook) | (1 << NF_INET_NUMHOOKS));
|
||||
|
||||
/* Unconditional return/END. */
|
||||
if ((e->target_offset == sizeof(struct ipt_entry) &&
|
||||
if ((unconditional(e) &&
|
||||
(strcmp(t->target.u.user.name,
|
||||
XT_STANDARD_TARGET) == 0) &&
|
||||
t->verdict < 0 && unconditional(&e->ip)) ||
|
||||
visited) {
|
||||
t->verdict < 0) || visited) {
|
||||
unsigned int oldpos, size;
|
||||
|
||||
if ((strcmp(t->target.u.user.name,
|
||||
@@ -560,14 +559,12 @@ static void cleanup_match(struct xt_entry_match *m, struct net *net)
|
||||
}
|
||||
|
||||
static int
|
||||
check_entry(const struct ipt_entry *e, const char *name)
|
||||
check_entry(const struct ipt_entry *e)
|
||||
{
|
||||
const struct xt_entry_target *t;
|
||||
|
||||
if (!ip_checkentry(&e->ip)) {
|
||||
duprintf("ip check failed %p %s.\n", e, name);
|
||||
if (!ip_checkentry(&e->ip))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (e->target_offset + sizeof(struct xt_entry_target) >
|
||||
e->next_offset)
|
||||
@@ -580,6 +577,7 @@ check_entry(const struct ipt_entry *e, const char *name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
check_match(struct xt_entry_match *m, struct xt_mtchk_param *par)
|
||||
{
|
||||
@@ -657,10 +655,6 @@ find_check_entry(struct ipt_entry *e, struct net *net, const char *name,
|
||||
struct xt_mtchk_param mtpar;
|
||||
struct xt_entry_match *ematch;
|
||||
|
||||
ret = check_entry(e, name);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
j = 0;
|
||||
mtpar.net = net;
|
||||
mtpar.table = name;
|
||||
@@ -704,7 +698,7 @@ static bool check_underflow(const struct ipt_entry *e)
|
||||
const struct xt_entry_target *t;
|
||||
unsigned int verdict;
|
||||
|
||||
if (!unconditional(&e->ip))
|
||||
if (!unconditional(e))
|
||||
return false;
|
||||
t = ipt_get_target_c(e);
|
||||
if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0)
|
||||
@@ -724,9 +718,11 @@ check_entry_size_and_hooks(struct ipt_entry *e,
|
||||
unsigned int valid_hooks)
|
||||
{
|
||||
unsigned int h;
|
||||
int err;
|
||||
|
||||
if ((unsigned long)e % __alignof__(struct ipt_entry) != 0 ||
|
||||
(unsigned char *)e + sizeof(struct ipt_entry) >= limit) {
|
||||
(unsigned char *)e + sizeof(struct ipt_entry) >= limit ||
|
||||
(unsigned char *)e + e->next_offset > limit) {
|
||||
duprintf("Bad offset %p\n", e);
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -738,6 +734,10 @@ check_entry_size_and_hooks(struct ipt_entry *e,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = check_entry(e);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Check hooks & underflows */
|
||||
for (h = 0; h < NF_INET_NUMHOOKS; h++) {
|
||||
if (!(valid_hooks & (1 << h)))
|
||||
@@ -1485,7 +1485,8 @@ check_compat_entry_size_and_hooks(struct compat_ipt_entry *e,
|
||||
|
||||
duprintf("check_compat_entry_size_and_hooks %p\n", e);
|
||||
if ((unsigned long)e % __alignof__(struct compat_ipt_entry) != 0 ||
|
||||
(unsigned char *)e + sizeof(struct compat_ipt_entry) >= limit) {
|
||||
(unsigned char *)e + sizeof(struct compat_ipt_entry) >= limit ||
|
||||
(unsigned char *)e + e->next_offset > limit) {
|
||||
duprintf("Bad offset %p, limit = %p\n", e, limit);
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -1498,7 +1499,7 @@ check_compat_entry_size_and_hooks(struct compat_ipt_entry *e,
|
||||
}
|
||||
|
||||
/* For purposes of check_entry casting the compat entry is fine */
|
||||
ret = check_entry((struct ipt_entry *)e, name);
|
||||
ret = check_entry((struct ipt_entry *)e);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
||||
+2
-1
@@ -154,6 +154,7 @@ void ping_unhash(struct sock *sk)
|
||||
if (sk_hashed(sk)) {
|
||||
write_lock_bh(&ping_table.lock);
|
||||
hlist_nulls_del(&sk->sk_nulls_node);
|
||||
sk_nulls_node_init(&sk->sk_nulls_node);
|
||||
sock_put(sk);
|
||||
isk->inet_num = 0;
|
||||
isk->inet_sport = 0;
|
||||
@@ -639,7 +640,7 @@ int ping_common_sendmsg(int family, struct msghdr *msg, size_t len,
|
||||
void *user_icmph, size_t icmph_len) {
|
||||
u8 type, code;
|
||||
|
||||
if (len > 0xFFFF)
|
||||
if (len > 0xFFFF || len < icmph_len)
|
||||
return -EMSGSIZE;
|
||||
|
||||
/*
|
||||
|
||||
+11
-3
@@ -68,6 +68,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/sysctl.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/reciprocal_div.h>
|
||||
#include <net/dst.h>
|
||||
#include <net/tcp.h>
|
||||
#include <net/inet_common.h>
|
||||
@@ -87,7 +88,7 @@ int sysctl_tcp_adv_win_scale __read_mostly = 1;
|
||||
EXPORT_SYMBOL(sysctl_tcp_adv_win_scale);
|
||||
|
||||
/* rfc5961 challenge ack rate limiting */
|
||||
int sysctl_tcp_challenge_ack_limit = 100;
|
||||
int sysctl_tcp_challenge_ack_limit = 1000;
|
||||
|
||||
int sysctl_tcp_stdurg __read_mostly;
|
||||
int sysctl_tcp_rfc1337 __read_mostly;
|
||||
@@ -3322,12 +3323,19 @@ static void tcp_send_challenge_ack(struct sock *sk)
|
||||
static u32 challenge_timestamp;
|
||||
static unsigned int challenge_count;
|
||||
u32 now = jiffies / HZ;
|
||||
u32 count;
|
||||
|
||||
if (now != challenge_timestamp) {
|
||||
u32 half = (sysctl_tcp_challenge_ack_limit + 1) >> 1;
|
||||
|
||||
challenge_timestamp = now;
|
||||
challenge_count = 0;
|
||||
ACCESS_ONCE(challenge_count) = half +
|
||||
reciprocal_divide(prandom_u32(),
|
||||
sysctl_tcp_challenge_ack_limit);
|
||||
}
|
||||
if (++challenge_count <= sysctl_tcp_challenge_ack_limit) {
|
||||
count = ACCESS_ONCE(challenge_count);
|
||||
if (count > 0) {
|
||||
ACCESS_ONCE(challenge_count) = count - 1;
|
||||
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPCHALLENGEACK);
|
||||
tcp_send_ack(sk);
|
||||
}
|
||||
|
||||
+6
-6
@@ -1249,6 +1249,7 @@ int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
|
||||
int peeked, off = 0;
|
||||
int err;
|
||||
int is_udplite = IS_UDPLITE(sk);
|
||||
bool checksum_valid = false;
|
||||
bool slow;
|
||||
|
||||
if (flags & MSG_ERRQUEUE)
|
||||
@@ -1274,11 +1275,12 @@ try_again:
|
||||
*/
|
||||
|
||||
if (copied < ulen || UDP_SKB_CB(skb)->partial_cov) {
|
||||
if (udp_lib_checksum_complete(skb))
|
||||
checksum_valid = !udp_lib_checksum_complete(skb);
|
||||
if (!checksum_valid)
|
||||
goto csum_copy_err;
|
||||
}
|
||||
|
||||
if (skb_csum_unnecessary(skb))
|
||||
if (checksum_valid || skb_csum_unnecessary(skb))
|
||||
err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr),
|
||||
msg->msg_iov, copied);
|
||||
else {
|
||||
@@ -1334,10 +1336,8 @@ csum_copy_err:
|
||||
}
|
||||
unlock_sock_fast(sk, slow);
|
||||
|
||||
if (noblock)
|
||||
return -EAGAIN;
|
||||
|
||||
/* starting over for a new packet */
|
||||
/* starting over for a new packet, but check if we need to yield */
|
||||
cond_resched();
|
||||
msg->msg_flags &= ~MSG_TRUNC;
|
||||
goto try_again;
|
||||
}
|
||||
|
||||
+7
-1
@@ -1193,7 +1193,13 @@ static void ndisc_router_discovery(struct sk_buff *skb)
|
||||
if (rt)
|
||||
rt6_set_expires(rt, jiffies + (HZ * lifetime));
|
||||
if (ra_msg->icmph.icmp6_hop_limit) {
|
||||
in6_dev->cnf.hop_limit = ra_msg->icmph.icmp6_hop_limit;
|
||||
/* Only set hop_limit on the interface if it is higher than
|
||||
* the current hop_limit.
|
||||
*/
|
||||
if (in6_dev->cnf.hop_limit < ra_msg->icmph.icmp6_hop_limit)
|
||||
in6_dev->cnf.hop_limit = ra_msg->icmph.icmp6_hop_limit;
|
||||
else
|
||||
ND_PRINTK(2, warn, "RA: Got route advertisement with lower hop_limit than current\n");
|
||||
if (rt)
|
||||
dst_metric_set(&rt->dst, RTAX_HOPLIMIT,
|
||||
ra_msg->icmph.icmp6_hop_limit);
|
||||
|
||||
@@ -195,13 +195,15 @@ get_entry(const void *base, unsigned int offset)
|
||||
|
||||
/* All zeroes == unconditional rule. */
|
||||
/* Mildly perf critical (only if packet tracing is on) */
|
||||
static inline bool unconditional(const struct ip6t_ip6 *ipv6)
|
||||
static inline bool unconditional(const struct ip6t_entry *e)
|
||||
{
|
||||
static const struct ip6t_ip6 uncond;
|
||||
|
||||
return memcmp(ipv6, &uncond, sizeof(uncond)) == 0;
|
||||
return e->target_offset == sizeof(struct ip6t_entry) &&
|
||||
memcmp(&e->ipv6, &uncond, sizeof(uncond)) == 0;
|
||||
}
|
||||
|
||||
|
||||
static inline const struct xt_entry_target *
|
||||
ip6t_get_target_c(const struct ip6t_entry *e)
|
||||
{
|
||||
@@ -255,11 +257,10 @@ get_chainname_rulenum(const struct ip6t_entry *s, const struct ip6t_entry *e,
|
||||
} else if (s == e) {
|
||||
(*rulenum)++;
|
||||
|
||||
if (s->target_offset == sizeof(struct ip6t_entry) &&
|
||||
if (unconditional(s) &&
|
||||
strcmp(t->target.u.kernel.target->name,
|
||||
XT_STANDARD_TARGET) == 0 &&
|
||||
t->verdict < 0 &&
|
||||
unconditional(&s->ipv6)) {
|
||||
t->verdict < 0) {
|
||||
/* Tail of chains: STANDARD target (return/policy) */
|
||||
*comment = *chainname == hookname
|
||||
? comments[NF_IP6_TRACE_COMMENT_POLICY]
|
||||
@@ -477,11 +478,10 @@ mark_source_chains(const struct xt_table_info *newinfo,
|
||||
e->comefrom |= ((1 << hook) | (1 << NF_INET_NUMHOOKS));
|
||||
|
||||
/* Unconditional return/END. */
|
||||
if ((e->target_offset == sizeof(struct ip6t_entry) &&
|
||||
if ((unconditional(e) &&
|
||||
(strcmp(t->target.u.user.name,
|
||||
XT_STANDARD_TARGET) == 0) &&
|
||||
t->verdict < 0 &&
|
||||
unconditional(&e->ipv6)) || visited) {
|
||||
t->verdict < 0) || visited) {
|
||||
unsigned int oldpos, size;
|
||||
|
||||
if ((strcmp(t->target.u.user.name,
|
||||
@@ -570,14 +570,12 @@ static void cleanup_match(struct xt_entry_match *m, struct net *net)
|
||||
}
|
||||
|
||||
static int
|
||||
check_entry(const struct ip6t_entry *e, const char *name)
|
||||
check_entry(const struct ip6t_entry *e)
|
||||
{
|
||||
const struct xt_entry_target *t;
|
||||
|
||||
if (!ip6_checkentry(&e->ipv6)) {
|
||||
duprintf("ip_tables: ip check failed %p %s.\n", e, name);
|
||||
if (!ip6_checkentry(&e->ipv6))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (e->target_offset + sizeof(struct xt_entry_target) >
|
||||
e->next_offset)
|
||||
@@ -590,6 +588,7 @@ check_entry(const struct ip6t_entry *e, const char *name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int check_match(struct xt_entry_match *m, struct xt_mtchk_param *par)
|
||||
{
|
||||
const struct ip6t_ip6 *ipv6 = par->entryinfo;
|
||||
@@ -668,10 +667,6 @@ find_check_entry(struct ip6t_entry *e, struct net *net, const char *name,
|
||||
struct xt_mtchk_param mtpar;
|
||||
struct xt_entry_match *ematch;
|
||||
|
||||
ret = check_entry(e, name);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
j = 0;
|
||||
mtpar.net = net;
|
||||
mtpar.table = name;
|
||||
@@ -715,7 +710,7 @@ static bool check_underflow(const struct ip6t_entry *e)
|
||||
const struct xt_entry_target *t;
|
||||
unsigned int verdict;
|
||||
|
||||
if (!unconditional(&e->ipv6))
|
||||
if (!unconditional(e))
|
||||
return false;
|
||||
t = ip6t_get_target_c(e);
|
||||
if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0)
|
||||
@@ -735,9 +730,11 @@ check_entry_size_and_hooks(struct ip6t_entry *e,
|
||||
unsigned int valid_hooks)
|
||||
{
|
||||
unsigned int h;
|
||||
int err;
|
||||
|
||||
if ((unsigned long)e % __alignof__(struct ip6t_entry) != 0 ||
|
||||
(unsigned char *)e + sizeof(struct ip6t_entry) >= limit) {
|
||||
(unsigned char *)e + sizeof(struct ip6t_entry) >= limit ||
|
||||
(unsigned char *)e + e->next_offset > limit) {
|
||||
duprintf("Bad offset %p\n", e);
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -749,6 +746,10 @@ check_entry_size_and_hooks(struct ip6t_entry *e,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = check_entry(e);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Check hooks & underflows */
|
||||
for (h = 0; h < NF_INET_NUMHOOKS; h++) {
|
||||
if (!(valid_hooks & (1 << h)))
|
||||
@@ -1497,7 +1498,8 @@ check_compat_entry_size_and_hooks(struct compat_ip6t_entry *e,
|
||||
|
||||
duprintf("check_compat_entry_size_and_hooks %p\n", e);
|
||||
if ((unsigned long)e % __alignof__(struct compat_ip6t_entry) != 0 ||
|
||||
(unsigned char *)e + sizeof(struct compat_ip6t_entry) >= limit) {
|
||||
(unsigned char *)e + sizeof(struct compat_ip6t_entry) >= limit ||
|
||||
(unsigned char *)e + e->next_offset > limit) {
|
||||
duprintf("Bad offset %p, limit = %p\n", e, limit);
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -1510,7 +1512,7 @@ check_compat_entry_size_and_hooks(struct compat_ip6t_entry *e,
|
||||
}
|
||||
|
||||
/* For purposes of check_entry casting the compat entry is fine */
|
||||
ret = check_entry((struct ip6t_entry *)e, name);
|
||||
ret = check_entry((struct ip6t_entry *)e);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
||||
+6
-6
@@ -370,6 +370,7 @@ int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk,
|
||||
int peeked, off = 0;
|
||||
int err;
|
||||
int is_udplite = IS_UDPLITE(sk);
|
||||
bool checksum_valid = false;
|
||||
int is_udp4;
|
||||
bool slow;
|
||||
|
||||
@@ -401,11 +402,12 @@ try_again:
|
||||
*/
|
||||
|
||||
if (copied < ulen || UDP_SKB_CB(skb)->partial_cov) {
|
||||
if (udp_lib_checksum_complete(skb))
|
||||
checksum_valid = !udp_lib_checksum_complete(skb);
|
||||
if (!checksum_valid)
|
||||
goto csum_copy_err;
|
||||
}
|
||||
|
||||
if (skb_csum_unnecessary(skb))
|
||||
if (checksum_valid || skb_csum_unnecessary(skb))
|
||||
err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr),
|
||||
msg->msg_iov, copied);
|
||||
else {
|
||||
@@ -494,10 +496,8 @@ csum_copy_err:
|
||||
}
|
||||
unlock_sock_fast(sk, slow);
|
||||
|
||||
if (noblock)
|
||||
return -EAGAIN;
|
||||
|
||||
/* starting over for a new packet */
|
||||
/* starting over for a new packet, but check if we need to yield */
|
||||
cond_resched();
|
||||
msg->msg_flags &= ~MSG_TRUNC;
|
||||
goto try_again;
|
||||
}
|
||||
|
||||
+3
-2
@@ -249,8 +249,6 @@ static int l2tp_ip_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
|
||||
int ret;
|
||||
int chk_addr_ret;
|
||||
|
||||
if (!sock_flag(sk, SOCK_ZAPPED))
|
||||
return -EINVAL;
|
||||
if (addr_len < sizeof(struct sockaddr_l2tpip))
|
||||
return -EINVAL;
|
||||
if (addr->l2tp_family != AF_INET)
|
||||
@@ -265,6 +263,9 @@ static int l2tp_ip_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
|
||||
read_unlock_bh(&l2tp_ip_lock);
|
||||
|
||||
lock_sock(sk);
|
||||
if (!sock_flag(sk, SOCK_ZAPPED))
|
||||
goto out;
|
||||
|
||||
if (sk->sk_state != TCP_CLOSE || addr_len < sizeof(struct sockaddr_l2tpip))
|
||||
goto out;
|
||||
|
||||
|
||||
+3
-2
@@ -264,8 +264,6 @@ static int l2tp_ip6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
|
||||
int addr_type;
|
||||
int err;
|
||||
|
||||
if (!sock_flag(sk, SOCK_ZAPPED))
|
||||
return -EINVAL;
|
||||
if (addr->l2tp_family != AF_INET6)
|
||||
return -EINVAL;
|
||||
if (addr_len < sizeof(*addr))
|
||||
@@ -291,6 +289,9 @@ static int l2tp_ip6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
|
||||
lock_sock(sk);
|
||||
|
||||
err = -EINVAL;
|
||||
if (!sock_flag(sk, SOCK_ZAPPED))
|
||||
goto out_unlock;
|
||||
|
||||
if (sk->sk_state != TCP_CLOSE)
|
||||
goto out_unlock;
|
||||
|
||||
|
||||
@@ -188,7 +188,7 @@ EXPORT_SYMBOL_GPL(nf_ct_invert_tuple);
|
||||
static void
|
||||
clean_from_lists(struct nf_conn *ct)
|
||||
{
|
||||
pr_debug("clean_from_lists(%p)\n", ct);
|
||||
pr_debug("clean_from_lists(%pK)\n", ct);
|
||||
hlist_nulls_del_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode);
|
||||
hlist_nulls_del_rcu(&ct->tuplehash[IP_CT_DIR_REPLY].hnnode);
|
||||
|
||||
@@ -203,7 +203,7 @@ destroy_conntrack(struct nf_conntrack *nfct)
|
||||
struct net *net = nf_ct_net(ct);
|
||||
struct nf_conntrack_l4proto *l4proto;
|
||||
|
||||
pr_debug("destroy_conntrack(%p)\n", ct);
|
||||
pr_debug("destroy_conntrack(%pK)\n", ct);
|
||||
NF_CT_ASSERT(atomic_read(&nfct->use) == 0);
|
||||
NF_CT_ASSERT(!timer_pending(&ct->timeout));
|
||||
|
||||
@@ -234,7 +234,7 @@ destroy_conntrack(struct nf_conntrack *nfct)
|
||||
if (ct->master)
|
||||
nf_ct_put(ct->master);
|
||||
|
||||
pr_debug("destroy_conntrack: returning ct=%p to slab\n", ct);
|
||||
pr_debug("destroy_conntrack: returning ct=%pK to slab\n", ct);
|
||||
nf_conntrack_free(ct);
|
||||
}
|
||||
|
||||
@@ -496,7 +496,7 @@ __nf_conntrack_confirm(struct sk_buff *skb)
|
||||
/* No external references means no one else could have
|
||||
confirmed us. */
|
||||
NF_CT_ASSERT(!nf_ct_is_confirmed(ct));
|
||||
pr_debug("Confirming conntrack %p\n", ct);
|
||||
pr_debug("Confirming conntrack %pK\n", ct);
|
||||
|
||||
spin_lock_bh(&nf_conntrack_lock);
|
||||
|
||||
@@ -823,7 +823,7 @@ init_conntrack(struct net *net, struct nf_conn *tmpl,
|
||||
spin_lock_bh(&nf_conntrack_lock);
|
||||
exp = nf_ct_find_expectation(net, zone, tuple);
|
||||
if (exp) {
|
||||
pr_debug("conntrack: expectation arrives ct=%p exp=%p\n",
|
||||
pr_debug("conntrack: expectation arrives ct=%pK exp=%pK\n",
|
||||
ct, exp);
|
||||
/* Welcome, Mr. Bond. We've been expecting you... */
|
||||
__set_bit(IPS_EXPECTED_BIT, &ct->status);
|
||||
@@ -909,14 +909,14 @@ resolve_normal_ct(struct net *net, struct nf_conn *tmpl,
|
||||
} else {
|
||||
/* Once we've had two way comms, always ESTABLISHED. */
|
||||
if (test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) {
|
||||
pr_debug("nf_conntrack_in: normal packet for %p\n", ct);
|
||||
pr_debug("nf_conntrack_in: normal packet for %pK\n", ct);
|
||||
*ctinfo = IP_CT_ESTABLISHED;
|
||||
} else if (test_bit(IPS_EXPECTED_BIT, &ct->status)) {
|
||||
pr_debug("nf_conntrack_in: related packet for %p\n",
|
||||
pr_debug("nf_conntrack_in: related packet for %pK\n",
|
||||
ct);
|
||||
*ctinfo = IP_CT_RELATED;
|
||||
} else {
|
||||
pr_debug("nf_conntrack_in: new packet for %p\n", ct);
|
||||
pr_debug("nf_conntrack_in: new packet for %pK\n", ct);
|
||||
*ctinfo = IP_CT_NEW;
|
||||
}
|
||||
*set_reply = 0;
|
||||
@@ -1058,7 +1058,7 @@ void nf_conntrack_alter_reply(struct nf_conn *ct,
|
||||
/* Should be unconfirmed, so not in hash table yet */
|
||||
NF_CT_ASSERT(!nf_ct_is_confirmed(ct));
|
||||
|
||||
pr_debug("Altering reply tuple of %p to ", ct);
|
||||
pr_debug("Altering reply tuple of %pK to ", ct);
|
||||
nf_ct_dump_tuple(newreply);
|
||||
|
||||
ct->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply;
|
||||
@@ -1628,7 +1628,7 @@ int nf_conntrack_init_net(struct net *net)
|
||||
goto err_stat;
|
||||
}
|
||||
|
||||
net->ct.slabname = kasprintf(GFP_KERNEL, "nf_conntrack_%p", net);
|
||||
net->ct.slabname = kasprintf(GFP_KERNEL, "nf_conntrack_%pK", net);
|
||||
if (!net->ct.slabname) {
|
||||
ret = -ENOMEM;
|
||||
goto err_slabname;
|
||||
|
||||
@@ -1934,7 +1934,7 @@ static int qtaguid_ctrl_proc_show(struct seq_file *m, void *v)
|
||||
);
|
||||
f_count = atomic_long_read(
|
||||
&sock_tag_entry->socket->file->f_count);
|
||||
seq_printf(m, "sock=%p tag=0x%llx (uid=%u) pid=%u "
|
||||
seq_printf(m, "sock=%pK tag=0x%llx (uid=%u) pid=%u "
|
||||
"f_count=%lu\n",
|
||||
sock_tag_entry->sk,
|
||||
sock_tag_entry->tag, uid,
|
||||
|
||||
+20
-6
@@ -3135,19 +3135,25 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
|
||||
|
||||
if (optlen != sizeof(val))
|
||||
return -EINVAL;
|
||||
if (po->rx_ring.pg_vec || po->tx_ring.pg_vec)
|
||||
return -EBUSY;
|
||||
if (copy_from_user(&val, optval, sizeof(val)))
|
||||
return -EFAULT;
|
||||
switch (val) {
|
||||
case TPACKET_V1:
|
||||
case TPACKET_V2:
|
||||
case TPACKET_V3:
|
||||
po->tp_version = val;
|
||||
return 0;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
lock_sock(sk);
|
||||
if (po->rx_ring.pg_vec || po->tx_ring.pg_vec) {
|
||||
ret = -EBUSY;
|
||||
} else {
|
||||
po->tp_version = val;
|
||||
ret = 0;
|
||||
}
|
||||
release_sock(sk);
|
||||
return ret;
|
||||
}
|
||||
case PACKET_RESERVE:
|
||||
{
|
||||
@@ -3159,6 +3165,8 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
|
||||
return -EBUSY;
|
||||
if (copy_from_user(&val, optval, sizeof(val)))
|
||||
return -EFAULT;
|
||||
if (val > INT_MAX)
|
||||
return -EINVAL;
|
||||
po->tp_reserve = val;
|
||||
return 0;
|
||||
}
|
||||
@@ -3602,6 +3610,7 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
|
||||
/* Added to avoid minimal code churn */
|
||||
struct tpacket_req *req = &req_u->req;
|
||||
|
||||
lock_sock(sk);
|
||||
/* Opening a Tx-ring is NOT supported in TPACKET_V3 */
|
||||
if (!closing && tx_ring && (po->tp_version > TPACKET_V2)) {
|
||||
WARN(1, "Tx-ring is not supported.\n");
|
||||
@@ -3642,6 +3651,10 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
|
||||
goto out;
|
||||
if (unlikely(req->tp_block_size & (PAGE_SIZE - 1)))
|
||||
goto out;
|
||||
if (po->tp_version >= TPACKET_V3 &&
|
||||
req->tp_block_size <=
|
||||
BLK_PLUS_PRIV((u64)req_u->req3.tp_sizeof_priv))
|
||||
goto out;
|
||||
if (unlikely(req->tp_frame_size < po->tp_hdrlen +
|
||||
po->tp_reserve))
|
||||
goto out;
|
||||
@@ -3651,6 +3664,8 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
|
||||
rb->frames_per_block = req->tp_block_size/req->tp_frame_size;
|
||||
if (unlikely(rb->frames_per_block <= 0))
|
||||
goto out;
|
||||
if (unlikely(req->tp_block_size > UINT_MAX / req->tp_block_nr))
|
||||
goto out;
|
||||
if (unlikely((rb->frames_per_block * req->tp_block_nr) !=
|
||||
req->tp_frame_nr))
|
||||
goto out;
|
||||
@@ -3679,7 +3694,6 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
|
||||
goto out;
|
||||
}
|
||||
|
||||
lock_sock(sk);
|
||||
|
||||
/* Detach socket from network */
|
||||
spin_lock(&po->bind_lock);
|
||||
@@ -3728,11 +3742,11 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
|
||||
if (!tx_ring)
|
||||
prb_shutdown_retire_blk_timer(po, tx_ring, rb_queue);
|
||||
}
|
||||
release_sock(sk);
|
||||
|
||||
if (pg_vec)
|
||||
free_pg_vec(pg_vec, order, req->tp_block_nr);
|
||||
out:
|
||||
release_sock(sk);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
+13
-8
@@ -1823,6 +1823,8 @@ SYSCALL_DEFINE6(sendto, int, fd, void __user *, buff, size_t, len,
|
||||
|
||||
if (len > INT_MAX)
|
||||
len = INT_MAX;
|
||||
if (unlikely(!access_ok(VERIFY_READ, buff, len)))
|
||||
return -EFAULT;
|
||||
sock = sockfd_lookup_light(fd, &err, &fput_needed);
|
||||
if (!sock)
|
||||
goto out;
|
||||
@@ -1882,6 +1884,8 @@ SYSCALL_DEFINE6(recvfrom, int, fd, void __user *, ubuf, size_t, size,
|
||||
|
||||
if (size > INT_MAX)
|
||||
size = INT_MAX;
|
||||
if (unlikely(!access_ok(VERIFY_WRITE, ubuf, size)))
|
||||
return -EFAULT;
|
||||
sock = sockfd_lookup_light(fd, &err, &fput_needed);
|
||||
if (!sock)
|
||||
goto out;
|
||||
@@ -2444,13 +2448,14 @@ int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
|
||||
break;
|
||||
}
|
||||
|
||||
out_put:
|
||||
fput_light(sock->file, fput_needed);
|
||||
|
||||
if (err == 0)
|
||||
return datagrams;
|
||||
goto out_put;
|
||||
|
||||
if (datagrams == 0) {
|
||||
datagrams = err;
|
||||
goto out_put;
|
||||
}
|
||||
|
||||
if (datagrams != 0) {
|
||||
/*
|
||||
* We may return less entries than requested (vlen) if the
|
||||
* sock is non block and there aren't enough datagrams...
|
||||
@@ -2465,10 +2470,10 @@ out_put:
|
||||
sock->sk->sk_err = -err;
|
||||
}
|
||||
|
||||
return datagrams;
|
||||
}
|
||||
out_put:
|
||||
fput_light(sock->file, fput_needed);
|
||||
|
||||
return err;
|
||||
return datagrams;
|
||||
}
|
||||
|
||||
SYSCALL_DEFINE5(recvmmsg, int, fd, struct mmsghdr __user *, mmsg,
|
||||
|
||||
+167
-19
@@ -334,6 +334,118 @@ found:
|
||||
return s;
|
||||
}
|
||||
|
||||
/* Support code for asymmetrically connected dgram sockets
|
||||
*
|
||||
* If a datagram socket is connected to a socket not itself connected
|
||||
* to the first socket (eg, /dev/log), clients may only enqueue more
|
||||
* messages if the present receive queue of the server socket is not
|
||||
* "too large". This means there's a second writeability condition
|
||||
* poll and sendmsg need to test. The dgram recv code will do a wake
|
||||
* up on the peer_wait wait queue of a socket upon reception of a
|
||||
* datagram which needs to be propagated to sleeping would-be writers
|
||||
* since these might not have sent anything so far. This can't be
|
||||
* accomplished via poll_wait because the lifetime of the server
|
||||
* socket might be less than that of its clients if these break their
|
||||
* association with it or if the server socket is closed while clients
|
||||
* are still connected to it and there's no way to inform "a polling
|
||||
* implementation" that it should let go of a certain wait queue
|
||||
*
|
||||
* In order to propagate a wake up, a wait_queue_t of the client
|
||||
* socket is enqueued on the peer_wait queue of the server socket
|
||||
* whose wake function does a wake_up on the ordinary client socket
|
||||
* wait queue. This connection is established whenever a write (or
|
||||
* poll for write) hit the flow control condition and broken when the
|
||||
* association to the server socket is dissolved or after a wake up
|
||||
* was relayed.
|
||||
*/
|
||||
|
||||
static int unix_dgram_peer_wake_relay(wait_queue_t *q, unsigned mode, int flags,
|
||||
void *key)
|
||||
{
|
||||
struct unix_sock *u;
|
||||
wait_queue_head_t *u_sleep;
|
||||
|
||||
u = container_of(q, struct unix_sock, peer_wake);
|
||||
|
||||
__remove_wait_queue(&unix_sk(u->peer_wake.private)->peer_wait,
|
||||
q);
|
||||
u->peer_wake.private = NULL;
|
||||
|
||||
/* relaying can only happen while the wq still exists */
|
||||
u_sleep = sk_sleep(&u->sk);
|
||||
if (u_sleep)
|
||||
wake_up_interruptible_poll(u_sleep, key);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int unix_dgram_peer_wake_connect(struct sock *sk, struct sock *other)
|
||||
{
|
||||
struct unix_sock *u, *u_other;
|
||||
int rc;
|
||||
|
||||
u = unix_sk(sk);
|
||||
u_other = unix_sk(other);
|
||||
rc = 0;
|
||||
spin_lock(&u_other->peer_wait.lock);
|
||||
|
||||
if (!u->peer_wake.private) {
|
||||
u->peer_wake.private = other;
|
||||
__add_wait_queue(&u_other->peer_wait, &u->peer_wake);
|
||||
|
||||
rc = 1;
|
||||
}
|
||||
|
||||
spin_unlock(&u_other->peer_wait.lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void unix_dgram_peer_wake_disconnect(struct sock *sk,
|
||||
struct sock *other)
|
||||
{
|
||||
struct unix_sock *u, *u_other;
|
||||
|
||||
u = unix_sk(sk);
|
||||
u_other = unix_sk(other);
|
||||
spin_lock(&u_other->peer_wait.lock);
|
||||
|
||||
if (u->peer_wake.private == other) {
|
||||
__remove_wait_queue(&u_other->peer_wait, &u->peer_wake);
|
||||
u->peer_wake.private = NULL;
|
||||
}
|
||||
|
||||
spin_unlock(&u_other->peer_wait.lock);
|
||||
}
|
||||
|
||||
static void unix_dgram_peer_wake_disconnect_wakeup(struct sock *sk,
|
||||
struct sock *other)
|
||||
{
|
||||
unix_dgram_peer_wake_disconnect(sk, other);
|
||||
wake_up_interruptible_poll(sk_sleep(sk),
|
||||
POLLOUT |
|
||||
POLLWRNORM |
|
||||
POLLWRBAND);
|
||||
}
|
||||
|
||||
/* preconditions:
|
||||
* - unix_peer(sk) == other
|
||||
* - association is stable
|
||||
*/
|
||||
static int unix_dgram_peer_wake_me(struct sock *sk, struct sock *other)
|
||||
{
|
||||
int connected;
|
||||
|
||||
connected = unix_dgram_peer_wake_connect(sk, other);
|
||||
|
||||
if (unix_recvq_full(other))
|
||||
return 1;
|
||||
|
||||
if (connected)
|
||||
unix_dgram_peer_wake_disconnect(sk, other);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int unix_writable(struct sock *sk)
|
||||
{
|
||||
return (atomic_read(&sk->sk_wmem_alloc) << 2) <= sk->sk_sndbuf;
|
||||
@@ -440,6 +552,8 @@ static void unix_release_sock(struct sock *sk, int embrion)
|
||||
skpair->sk_state_change(skpair);
|
||||
sk_wake_async(skpair, SOCK_WAKE_WAITD, POLL_HUP);
|
||||
}
|
||||
|
||||
unix_dgram_peer_wake_disconnect(sk, skpair);
|
||||
sock_put(skpair); /* It may now die */
|
||||
unix_peer(sk) = NULL;
|
||||
}
|
||||
@@ -674,6 +788,7 @@ static struct sock *unix_create1(struct net *net, struct socket *sock)
|
||||
INIT_LIST_HEAD(&u->link);
|
||||
mutex_init(&u->readlock); /* single task reading lock */
|
||||
init_waitqueue_head(&u->peer_wait);
|
||||
init_waitqueue_func_entry(&u->peer_wake, unix_dgram_peer_wake_relay);
|
||||
unix_insert_socket(unix_sockets_unbound(sk), sk);
|
||||
out:
|
||||
if (sk == NULL)
|
||||
@@ -1044,6 +1159,8 @@ restart:
|
||||
if (unix_peer(sk)) {
|
||||
struct sock *old_peer = unix_peer(sk);
|
||||
unix_peer(sk) = other;
|
||||
unix_dgram_peer_wake_disconnect_wakeup(sk, old_peer);
|
||||
|
||||
unix_state_double_unlock(sk, other);
|
||||
|
||||
if (other != old_peer)
|
||||
@@ -1504,6 +1621,7 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock,
|
||||
struct scm_cookie tmp_scm;
|
||||
int max_level;
|
||||
int data_len = 0;
|
||||
int sk_locked;
|
||||
|
||||
if (NULL == siocb->scm)
|
||||
siocb->scm = &tmp_scm;
|
||||
@@ -1580,12 +1698,14 @@ restart:
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
sk_locked = 0;
|
||||
unix_state_lock(other);
|
||||
restart_locked:
|
||||
err = -EPERM;
|
||||
if (!unix_may_send(sk, other))
|
||||
goto out_unlock;
|
||||
|
||||
if (sock_flag(other, SOCK_DEAD)) {
|
||||
if (unlikely(sock_flag(other, SOCK_DEAD))) {
|
||||
/*
|
||||
* Check with 1003.1g - what should
|
||||
* datagram error
|
||||
@@ -1593,10 +1713,12 @@ restart:
|
||||
unix_state_unlock(other);
|
||||
sock_put(other);
|
||||
|
||||
err = 0;
|
||||
if (!sk_locked)
|
||||
unix_state_lock(sk);
|
||||
if (unix_peer(sk) == other) {
|
||||
unix_peer(sk) = NULL;
|
||||
unix_dgram_peer_wake_disconnect_wakeup(sk, other);
|
||||
|
||||
unix_state_unlock(sk);
|
||||
|
||||
unix_dgram_disconnected(sk, other);
|
||||
@@ -1622,21 +1744,43 @@ restart:
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
if (unix_peer(other) != sk && unix_recvq_full(other)) {
|
||||
if (!timeo) {
|
||||
/* other == sk && unix_peer(other) != sk if
|
||||
* - unix_peer(sk) == NULL, destination address bound to sk
|
||||
* - unix_peer(sk) == sk by time of get but disconnected before lock
|
||||
*/
|
||||
if (other != sk &&
|
||||
unlikely(unix_peer(other) != sk && unix_recvq_full(other))) {
|
||||
if (timeo) {
|
||||
timeo = unix_wait_for_peer(other, timeo);
|
||||
|
||||
err = sock_intr_errno(timeo);
|
||||
if (signal_pending(current))
|
||||
goto out_free;
|
||||
|
||||
goto restart;
|
||||
}
|
||||
|
||||
if (!sk_locked) {
|
||||
unix_state_unlock(other);
|
||||
unix_state_double_lock(sk, other);
|
||||
}
|
||||
|
||||
if (unix_peer(sk) != other ||
|
||||
unix_dgram_peer_wake_me(sk, other)) {
|
||||
err = -EAGAIN;
|
||||
sk_locked = 1;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
timeo = unix_wait_for_peer(other, timeo);
|
||||
|
||||
err = sock_intr_errno(timeo);
|
||||
if (signal_pending(current))
|
||||
goto out_free;
|
||||
|
||||
goto restart;
|
||||
if (!sk_locked) {
|
||||
sk_locked = 1;
|
||||
goto restart_locked;
|
||||
}
|
||||
}
|
||||
|
||||
if (unlikely(sk_locked))
|
||||
unix_state_unlock(sk);
|
||||
|
||||
if (sock_flag(other, SOCK_RCVTSTAMP))
|
||||
__net_timestamp(skb);
|
||||
maybe_add_creds(skb, sock, other);
|
||||
@@ -1651,6 +1795,8 @@ restart:
|
||||
return len;
|
||||
|
||||
out_unlock:
|
||||
if (sk_locked)
|
||||
unix_state_unlock(sk);
|
||||
unix_state_unlock(other);
|
||||
out_free:
|
||||
kfree_skb(skb);
|
||||
@@ -2368,14 +2514,16 @@ static unsigned int unix_dgram_poll(struct file *file, struct socket *sock,
|
||||
}
|
||||
|
||||
writable = unix_writable(sk);
|
||||
other = unix_peer_get(sk);
|
||||
if (other) {
|
||||
if (unix_peer(other) != sk) {
|
||||
sock_poll_wait(file, &unix_sk(other)->peer_wait, wait);
|
||||
if (unix_recvq_full(other))
|
||||
writable = 0;
|
||||
}
|
||||
sock_put(other);
|
||||
if (writable) {
|
||||
unix_state_lock(sk);
|
||||
|
||||
other = unix_peer(sk);
|
||||
if (other && unix_peer(other) != sk &&
|
||||
unix_recvq_full(other) &&
|
||||
unix_dgram_peer_wake_me(sk, other))
|
||||
writable = 0;
|
||||
|
||||
unix_state_unlock(sk);
|
||||
}
|
||||
|
||||
if (writable)
|
||||
|
||||
@@ -390,7 +390,14 @@ static inline int xfrm_replay_verify_len(struct xfrm_replay_state_esn *replay_es
|
||||
up = nla_data(rp);
|
||||
ulen = xfrm_replay_state_esn_len(up);
|
||||
|
||||
if (nla_len(rp) < ulen || xfrm_replay_state_esn_len(replay_esn) != ulen)
|
||||
/* Check the overall length and the internal bitmap length to avoid
|
||||
* potential overflow. */
|
||||
if (nla_len(rp) < ulen ||
|
||||
xfrm_replay_state_esn_len(replay_esn) != ulen ||
|
||||
replay_esn->bmp_len != up->bmp_len)
|
||||
return -EINVAL;
|
||||
|
||||
if (up->replay_window > up->bmp_len * sizeof(__u32) * 8)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user