]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
5.1-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 3 Jul 2019 12:22:35 +0000 (14:22 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 3 Jul 2019 12:22:35 +0000 (14:22 +0200)
added patches:
bluetooth-fix-faulty-expression-for-minimum-encryption-key-size-check.patch
netfilter-nf_flow_table-ignore-df-bit-setting.patch
netfilter-nft_flow_offload-don-t-offload-when-sequence-numbers-need-adjustment.patch
netfilter-nft_flow_offload-ipcb-is-only-valid-for-ipv4-family.patch
netfilter-nft_flow_offload-set-liberal-tracking-mode-for-tcp.patch
signal-remove-the-wrong-signal_pending-check-in-restore_user_sigmask.patch

queue-5.1/bluetooth-fix-faulty-expression-for-minimum-encryption-key-size-check.patch [new file with mode: 0644]
queue-5.1/netfilter-nf_flow_table-ignore-df-bit-setting.patch [new file with mode: 0644]
queue-5.1/netfilter-nft_flow_offload-don-t-offload-when-sequence-numbers-need-adjustment.patch [new file with mode: 0644]
queue-5.1/netfilter-nft_flow_offload-ipcb-is-only-valid-for-ipv4-family.patch [new file with mode: 0644]
queue-5.1/netfilter-nft_flow_offload-set-liberal-tracking-mode-for-tcp.patch [new file with mode: 0644]
queue-5.1/signal-remove-the-wrong-signal_pending-check-in-restore_user_sigmask.patch [new file with mode: 0644]

diff --git a/queue-5.1/bluetooth-fix-faulty-expression-for-minimum-encryption-key-size-check.patch b/queue-5.1/bluetooth-fix-faulty-expression-for-minimum-encryption-key-size-check.patch
new file mode 100644 (file)
index 0000000..b0ec204
--- /dev/null
@@ -0,0 +1,38 @@
+From eca94432934fe5f141d084f2e36ee2c0e614cc04 Mon Sep 17 00:00:00 2001
+From: Matias Karhumaa <matias.karhumaa@gmail.com>
+Date: Tue, 2 Jul 2019 16:35:09 +0200
+Subject: Bluetooth: Fix faulty expression for minimum encryption key size check
+
+From: Matias Karhumaa <matias.karhumaa@gmail.com>
+
+commit eca94432934fe5f141d084f2e36ee2c0e614cc04 upstream.
+
+Fix minimum encryption key size check so that HCI_MIN_ENC_KEY_SIZE is
+also allowed as stated in the comment.
+
+This bug caused connection problems with devices having maximum
+encryption key size of 7 octets (56-bit).
+
+Fixes: 693cd8ce3f88 ("Bluetooth: Fix regression with minimum encryption key size alignment")
+Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=203997
+Signed-off-by: Matias Karhumaa <matias.karhumaa@gmail.com>
+Cc: stable@vger.kernel.org
+Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ net/bluetooth/l2cap_core.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/net/bluetooth/l2cap_core.c
++++ b/net/bluetooth/l2cap_core.c
+@@ -1353,7 +1353,7 @@ static bool l2cap_check_enc_key_size(str
+        * actually encrypted before enforcing a key size.
+        */
+       return (!test_bit(HCI_CONN_ENCRYPT, &hcon->flags) ||
+-              hcon->enc_key_size > HCI_MIN_ENC_KEY_SIZE);
++              hcon->enc_key_size >= HCI_MIN_ENC_KEY_SIZE);
+ }
+ static void l2cap_do_start(struct l2cap_chan *chan)
diff --git a/queue-5.1/netfilter-nf_flow_table-ignore-df-bit-setting.patch b/queue-5.1/netfilter-nf_flow_table-ignore-df-bit-setting.patch
new file mode 100644 (file)
index 0000000..92f9214
--- /dev/null
@@ -0,0 +1,37 @@
+From e75b3e1c9bc5b997d09bdf8eb72ab3dd3c1a7072 Mon Sep 17 00:00:00 2001
+From: Florian Westphal <fw@strlen.de>
+Date: Tue, 21 May 2019 13:24:30 +0200
+Subject: netfilter: nf_flow_table: ignore DF bit setting
+
+From: Florian Westphal <fw@strlen.de>
+
+commit e75b3e1c9bc5b997d09bdf8eb72ab3dd3c1a7072 upstream.
+
+Its irrelevant if the DF bit is set or not, we must pass packet to
+stack in either case.
+
+If the DF bit is set, we must pass it to stack so the appropriate
+ICMP error can be generated.
+
+If the DF is not set, we must pass it to stack for fragmentation.
+
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ net/netfilter/nf_flow_table_ip.c |    3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- a/net/netfilter/nf_flow_table_ip.c
++++ b/net/netfilter/nf_flow_table_ip.c
+@@ -246,8 +246,7 @@ nf_flow_offload_ip_hook(void *priv, stru
+       flow = container_of(tuplehash, struct flow_offload, tuplehash[dir]);
+       rt = (struct rtable *)flow->tuplehash[dir].tuple.dst_cache;
+-      if (unlikely(nf_flow_exceeds_mtu(skb, flow->tuplehash[dir].tuple.mtu)) &&
+-          (ip_hdr(skb)->frag_off & htons(IP_DF)) != 0)
++      if (unlikely(nf_flow_exceeds_mtu(skb, flow->tuplehash[dir].tuple.mtu)))
+               return NF_ACCEPT;
+       if (skb_try_make_writable(skb, sizeof(*iph)))
diff --git a/queue-5.1/netfilter-nft_flow_offload-don-t-offload-when-sequence-numbers-need-adjustment.patch b/queue-5.1/netfilter-nft_flow_offload-don-t-offload-when-sequence-numbers-need-adjustment.patch
new file mode 100644 (file)
index 0000000..087b9dc
--- /dev/null
@@ -0,0 +1,50 @@
+From 91a9048f238063dde7feea752b9dd386f7e3808b Mon Sep 17 00:00:00 2001
+From: Florian Westphal <fw@strlen.de>
+Date: Tue, 21 May 2019 13:24:32 +0200
+Subject: netfilter: nft_flow_offload: don't offload when sequence numbers need adjustment
+
+From: Florian Westphal <fw@strlen.de>
+
+commit 91a9048f238063dde7feea752b9dd386f7e3808b upstream.
+
+We can't deal with tcp sequence number rewrite in flow_offload.
+While at it, simplify helper check, we only need to know if the extension
+is present, we don't need the helper data.
+
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ net/netfilter/nft_flow_offload.c |    6 ++----
+ 1 file changed, 2 insertions(+), 4 deletions(-)
+
+--- a/net/netfilter/nft_flow_offload.c
++++ b/net/netfilter/nft_flow_offload.c
+@@ -12,7 +12,6 @@
+ #include <net/netfilter/nf_conntrack_core.h>
+ #include <linux/netfilter/nf_conntrack_common.h>
+ #include <net/netfilter/nf_flow_table.h>
+-#include <net/netfilter/nf_conntrack_helper.h>
+ struct nft_flow_offload {
+       struct nft_flowtable    *flowtable;
+@@ -67,7 +66,6 @@ static void nft_flow_offload_eval(const
+ {
+       struct nft_flow_offload *priv = nft_expr_priv(expr);
+       struct nf_flowtable *flowtable = &priv->flowtable->data;
+-      const struct nf_conn_help *help;
+       enum ip_conntrack_info ctinfo;
+       struct nf_flow_route route;
+       struct flow_offload *flow;
+@@ -93,8 +91,8 @@ static void nft_flow_offload_eval(const
+               goto out;
+       }
+-      help = nfct_help(ct);
+-      if (help)
++      if (nf_ct_ext_exist(ct, NF_CT_EXT_HELPER) ||
++          ct->status & IPS_SEQ_ADJUST)
+               goto out;
+       if (ctinfo == IP_CT_NEW ||
diff --git a/queue-5.1/netfilter-nft_flow_offload-ipcb-is-only-valid-for-ipv4-family.patch b/queue-5.1/netfilter-nft_flow_offload-ipcb-is-only-valid-for-ipv4-family.patch
new file mode 100644 (file)
index 0000000..96043d9
--- /dev/null
@@ -0,0 +1,56 @@
+From 69aeb538587e087bfc81dd1f465eab3558ff3158 Mon Sep 17 00:00:00 2001
+From: Florian Westphal <fw@strlen.de>
+Date: Tue, 21 May 2019 13:24:33 +0200
+Subject: netfilter: nft_flow_offload: IPCB is only valid for ipv4 family
+
+From: Florian Westphal <fw@strlen.de>
+
+commit 69aeb538587e087bfc81dd1f465eab3558ff3158 upstream.
+
+Guard this with a check vs. ipv4, IPCB isn't valid in ipv6 case.
+
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ net/netfilter/nft_flow_offload.c |   17 +++++++++++------
+ 1 file changed, 11 insertions(+), 6 deletions(-)
+
+--- a/net/netfilter/nft_flow_offload.c
++++ b/net/netfilter/nft_flow_offload.c
+@@ -48,15 +48,20 @@ static int nft_flow_route(const struct n
+       return 0;
+ }
+-static bool nft_flow_offload_skip(struct sk_buff *skb)
++static bool nft_flow_offload_skip(struct sk_buff *skb, int family)
+ {
+-      struct ip_options *opt  = &(IPCB(skb)->opt);
+-
+-      if (unlikely(opt->optlen))
+-              return true;
+       if (skb_sec_path(skb))
+               return true;
++      if (family == NFPROTO_IPV4) {
++              const struct ip_options *opt;
++
++              opt = &(IPCB(skb)->opt);
++
++              if (unlikely(opt->optlen))
++                      return true;
++      }
++
+       return false;
+ }
+@@ -74,7 +79,7 @@ static void nft_flow_offload_eval(const
+       struct nf_conn *ct;
+       int ret;
+-      if (nft_flow_offload_skip(pkt->skb))
++      if (nft_flow_offload_skip(pkt->skb, nft_pf(pkt)))
+               goto out;
+       ct = nf_ct_get(pkt->skb, &ctinfo);
diff --git a/queue-5.1/netfilter-nft_flow_offload-set-liberal-tracking-mode-for-tcp.patch b/queue-5.1/netfilter-nft_flow_offload-set-liberal-tracking-mode-for-tcp.patch
new file mode 100644 (file)
index 0000000..7df0871
--- /dev/null
@@ -0,0 +1,52 @@
+From 8437a6209f76f85a2db1abb12a9bde2170801617 Mon Sep 17 00:00:00 2001
+From: Florian Westphal <fw@strlen.de>
+Date: Tue, 21 May 2019 13:24:31 +0200
+Subject: netfilter: nft_flow_offload: set liberal tracking mode for tcp
+
+From: Florian Westphal <fw@strlen.de>
+
+commit 8437a6209f76f85a2db1abb12a9bde2170801617 upstream.
+
+Without it, whenever a packet has to be pushed up the stack (e.g. because
+of mtu mismatch), then conntrack will flag packets as invalid, which in
+turn breaks NAT.
+
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ net/netfilter/nft_flow_offload.c |    8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+--- a/net/netfilter/nft_flow_offload.c
++++ b/net/netfilter/nft_flow_offload.c
+@@ -72,6 +72,7 @@ static void nft_flow_offload_eval(const
+       struct nf_flow_route route;
+       struct flow_offload *flow;
+       enum ip_conntrack_dir dir;
++      bool is_tcp = false;
+       struct nf_conn *ct;
+       int ret;
+@@ -84,6 +85,8 @@ static void nft_flow_offload_eval(const
+       switch (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum) {
+       case IPPROTO_TCP:
++              is_tcp = true;
++              break;
+       case IPPROTO_UDP:
+               break;
+       default:
+@@ -109,6 +112,11 @@ static void nft_flow_offload_eval(const
+       if (!flow)
+               goto err_flow_alloc;
++      if (is_tcp) {
++              ct->proto.tcp.seen[0].flags |= IP_CT_TCP_FLAG_BE_LIBERAL;
++              ct->proto.tcp.seen[1].flags |= IP_CT_TCP_FLAG_BE_LIBERAL;
++      }
++
+       ret = flow_offload_add(flowtable, flow);
+       if (ret < 0)
+               goto err_flow_add;
diff --git a/queue-5.1/signal-remove-the-wrong-signal_pending-check-in-restore_user_sigmask.patch b/queue-5.1/signal-remove-the-wrong-signal_pending-check-in-restore_user_sigmask.patch
new file mode 100644 (file)
index 0000000..ac5c86f
--- /dev/null
@@ -0,0 +1,280 @@
+From 97abc889ee296faf95ca0e978340fb7b942a3e32 Mon Sep 17 00:00:00 2001
+From: Oleg Nesterov <oleg@redhat.com>
+Date: Fri, 28 Jun 2019 12:06:50 -0700
+Subject: signal: remove the wrong signal_pending() check in restore_user_sigmask()
+
+From: Oleg Nesterov <oleg@redhat.com>
+
+commit 97abc889ee296faf95ca0e978340fb7b942a3e32 upstream.
+
+This is the minimal fix for stable, I'll send cleanups later.
+
+Commit 854a6ed56839 ("signal: Add restore_user_sigmask()") introduced
+the visible change which breaks user-space: a signal temporary unblocked
+by set_user_sigmask() can be delivered even if the caller returns
+success or timeout.
+
+Change restore_user_sigmask() to accept the additional "interrupted"
+argument which should be used instead of signal_pending() check, and
+update the callers.
+
+Eric said:
+
+: For clarity.  I don't think this is required by posix, or fundamentally to
+: remove the races in select.  It is what linux has always done and we have
+: applications who care so I agree this fix is needed.
+:
+: Further in any case where the semantic change that this patch rolls back
+: (aka where allowing a signal to be delivered and the select like call to
+: complete) would be advantage we can do as well if not better by using
+: signalfd.
+:
+: Michael is there any chance we can get this guarantee of the linux
+: implementation of pselect and friends clearly documented.  The guarantee
+: that if the system call completes successfully we are guaranteed that no
+: signal that is unblocked by using sigmask will be delivered?
+
+Link: http://lkml.kernel.org/r/20190604134117.GA29963@redhat.com
+Fixes: 854a6ed56839a40f6b5d02a2962f48841482eec4 ("signal: Add restore_user_sigmask()")
+Signed-off-by: Oleg Nesterov <oleg@redhat.com>
+Reported-by: Eric Wong <e@80x24.org>
+Tested-by: Eric Wong <e@80x24.org>
+Acked-by: "Eric W. Biederman" <ebiederm@xmission.com>
+Acked-by: Arnd Bergmann <arnd@arndb.de>
+Acked-by: Deepa Dinamani <deepa.kernel@gmail.com>
+Cc: Michael Kerrisk <mtk.manpages@gmail.com>
+Cc: Jens Axboe <axboe@kernel.dk>
+Cc: Davidlohr Bueso <dave@stgolabs.net>
+Cc: Jason Baron <jbaron@akamai.com>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+Cc: Al Viro <viro@ZenIV.linux.org.uk>
+Cc: David Laight <David.Laight@ACULAB.COM>
+Cc: <stable@vger.kernel.org>   [5.0+]
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/aio.c               |   28 ++++++++++++++++++++--------
+ fs/eventpoll.c         |    4 ++--
+ fs/io_uring.c          |    2 +-
+ fs/select.c            |   18 ++++++------------
+ include/linux/signal.h |    2 +-
+ kernel/signal.c        |    5 +++--
+ 6 files changed, 33 insertions(+), 26 deletions(-)
+
+--- a/fs/aio.c
++++ b/fs/aio.c
+@@ -2095,6 +2095,7 @@ SYSCALL_DEFINE6(io_pgetevents,
+       struct __aio_sigset     ksig = { NULL, };
+       sigset_t                ksigmask, sigsaved;
+       struct timespec64       ts;
++      bool interrupted;
+       int ret;
+       if (timeout && unlikely(get_timespec64(&ts, timeout)))
+@@ -2108,8 +2109,10 @@ SYSCALL_DEFINE6(io_pgetevents,
+               return ret;
+       ret = do_io_getevents(ctx_id, min_nr, nr, events, timeout ? &ts : NULL);
+-      restore_user_sigmask(ksig.sigmask, &sigsaved);
+-      if (signal_pending(current) && !ret)
++
++      interrupted = signal_pending(current);
++      restore_user_sigmask(ksig.sigmask, &sigsaved, interrupted);
++      if (interrupted && !ret)
+               ret = -ERESTARTNOHAND;
+       return ret;
+@@ -2128,6 +2131,7 @@ SYSCALL_DEFINE6(io_pgetevents_time32,
+       struct __aio_sigset     ksig = { NULL, };
+       sigset_t                ksigmask, sigsaved;
+       struct timespec64       ts;
++      bool interrupted;
+       int ret;
+       if (timeout && unlikely(get_old_timespec32(&ts, timeout)))
+@@ -2142,8 +2146,10 @@ SYSCALL_DEFINE6(io_pgetevents_time32,
+               return ret;
+       ret = do_io_getevents(ctx_id, min_nr, nr, events, timeout ? &ts : NULL);
+-      restore_user_sigmask(ksig.sigmask, &sigsaved);
+-      if (signal_pending(current) && !ret)
++
++      interrupted = signal_pending(current);
++      restore_user_sigmask(ksig.sigmask, &sigsaved, interrupted);
++      if (interrupted && !ret)
+               ret = -ERESTARTNOHAND;
+       return ret;
+@@ -2193,6 +2199,7 @@ COMPAT_SYSCALL_DEFINE6(io_pgetevents,
+       struct __compat_aio_sigset ksig = { NULL, };
+       sigset_t ksigmask, sigsaved;
+       struct timespec64 t;
++      bool interrupted;
+       int ret;
+       if (timeout && get_old_timespec32(&t, timeout))
+@@ -2206,8 +2213,10 @@ COMPAT_SYSCALL_DEFINE6(io_pgetevents,
+               return ret;
+       ret = do_io_getevents(ctx_id, min_nr, nr, events, timeout ? &t : NULL);
+-      restore_user_sigmask(ksig.sigmask, &sigsaved);
+-      if (signal_pending(current) && !ret)
++
++      interrupted = signal_pending(current);
++      restore_user_sigmask(ksig.sigmask, &sigsaved, interrupted);
++      if (interrupted && !ret)
+               ret = -ERESTARTNOHAND;
+       return ret;
+@@ -2226,6 +2235,7 @@ COMPAT_SYSCALL_DEFINE6(io_pgetevents_tim
+       struct __compat_aio_sigset ksig = { NULL, };
+       sigset_t ksigmask, sigsaved;
+       struct timespec64 t;
++      bool interrupted;
+       int ret;
+       if (timeout && get_timespec64(&t, timeout))
+@@ -2239,8 +2249,10 @@ COMPAT_SYSCALL_DEFINE6(io_pgetevents_tim
+               return ret;
+       ret = do_io_getevents(ctx_id, min_nr, nr, events, timeout ? &t : NULL);
+-      restore_user_sigmask(ksig.sigmask, &sigsaved);
+-      if (signal_pending(current) && !ret)
++
++      interrupted = signal_pending(current);
++      restore_user_sigmask(ksig.sigmask, &sigsaved, interrupted);
++      if (interrupted && !ret)
+               ret = -ERESTARTNOHAND;
+       return ret;
+--- a/fs/eventpoll.c
++++ b/fs/eventpoll.c
+@@ -2330,7 +2330,7 @@ SYSCALL_DEFINE6(epoll_pwait, int, epfd,
+       error = do_epoll_wait(epfd, events, maxevents, timeout);
+-      restore_user_sigmask(sigmask, &sigsaved);
++      restore_user_sigmask(sigmask, &sigsaved, error == -EINTR);
+       return error;
+ }
+@@ -2355,7 +2355,7 @@ COMPAT_SYSCALL_DEFINE6(epoll_pwait, int,
+       err = do_epoll_wait(epfd, events, maxevents, timeout);
+-      restore_user_sigmask(sigmask, &sigsaved);
++      restore_user_sigmask(sigmask, &sigsaved, err == -EINTR);
+       return err;
+ }
+--- a/fs/io_uring.c
++++ b/fs/io_uring.c
+@@ -2096,7 +2096,7 @@ static int io_cqring_wait(struct io_ring
+       finish_wait(&ctx->wait, &wait);
+       if (sig)
+-              restore_user_sigmask(sig, &sigsaved);
++              restore_user_sigmask(sig, &sigsaved, ret == -EINTR);
+       return READ_ONCE(ring->r.head) == READ_ONCE(ring->r.tail) ? ret : 0;
+ }
+--- a/fs/select.c
++++ b/fs/select.c
+@@ -758,10 +758,9 @@ static long do_pselect(int n, fd_set __u
+               return ret;
+       ret = core_sys_select(n, inp, outp, exp, to);
++      restore_user_sigmask(sigmask, &sigsaved, ret == -ERESTARTNOHAND);
+       ret = poll_select_copy_remaining(&end_time, tsp, type, ret);
+-      restore_user_sigmask(sigmask, &sigsaved);
+-
+       return ret;
+ }
+@@ -1106,8 +1105,7 @@ SYSCALL_DEFINE5(ppoll, struct pollfd __u
+       ret = do_sys_poll(ufds, nfds, to);
+-      restore_user_sigmask(sigmask, &sigsaved);
+-
++      restore_user_sigmask(sigmask, &sigsaved, ret == -EINTR);
+       /* We can restart this syscall, usually */
+       if (ret == -EINTR)
+               ret = -ERESTARTNOHAND;
+@@ -1142,8 +1140,7 @@ SYSCALL_DEFINE5(ppoll_time32, struct pol
+       ret = do_sys_poll(ufds, nfds, to);
+-      restore_user_sigmask(sigmask, &sigsaved);
+-
++      restore_user_sigmask(sigmask, &sigsaved, ret == -EINTR);
+       /* We can restart this syscall, usually */
+       if (ret == -EINTR)
+               ret = -ERESTARTNOHAND;
+@@ -1350,10 +1347,9 @@ static long do_compat_pselect(int n, com
+               return ret;
+       ret = compat_core_sys_select(n, inp, outp, exp, to);
++      restore_user_sigmask(sigmask, &sigsaved, ret == -ERESTARTNOHAND);
+       ret = poll_select_copy_remaining(&end_time, tsp, type, ret);
+-      restore_user_sigmask(sigmask, &sigsaved);
+-
+       return ret;
+ }
+@@ -1425,8 +1421,7 @@ COMPAT_SYSCALL_DEFINE5(ppoll_time32, str
+       ret = do_sys_poll(ufds, nfds, to);
+-      restore_user_sigmask(sigmask, &sigsaved);
+-
++      restore_user_sigmask(sigmask, &sigsaved, ret == -EINTR);
+       /* We can restart this syscall, usually */
+       if (ret == -EINTR)
+               ret = -ERESTARTNOHAND;
+@@ -1461,8 +1456,7 @@ COMPAT_SYSCALL_DEFINE5(ppoll_time64, str
+       ret = do_sys_poll(ufds, nfds, to);
+-      restore_user_sigmask(sigmask, &sigsaved);
+-
++      restore_user_sigmask(sigmask, &sigsaved, ret == -EINTR);
+       /* We can restart this syscall, usually */
+       if (ret == -EINTR)
+               ret = -ERESTARTNOHAND;
+--- a/include/linux/signal.h
++++ b/include/linux/signal.h
+@@ -276,7 +276,7 @@ extern int sigprocmask(int, sigset_t *,
+ extern int set_user_sigmask(const sigset_t __user *usigmask, sigset_t *set,
+       sigset_t *oldset, size_t sigsetsize);
+ extern void restore_user_sigmask(const void __user *usigmask,
+-                               sigset_t *sigsaved);
++                               sigset_t *sigsaved, bool interrupted);
+ extern void set_current_blocked(sigset_t *);
+ extern void __set_current_blocked(const sigset_t *);
+ extern int show_unhandled_signals;
+--- a/kernel/signal.c
++++ b/kernel/signal.c
+@@ -2851,7 +2851,8 @@ EXPORT_SYMBOL(set_compat_user_sigmask);
+  * This is useful for syscalls such as ppoll, pselect, io_pgetevents and
+  * epoll_pwait where a new sigmask is passed in from userland for the syscalls.
+  */
+-void restore_user_sigmask(const void __user *usigmask, sigset_t *sigsaved)
++void restore_user_sigmask(const void __user *usigmask, sigset_t *sigsaved,
++                              bool interrupted)
+ {
+       if (!usigmask)
+@@ -2861,7 +2862,7 @@ void restore_user_sigmask(const void __u
+        * Restoring sigmask here can lead to delivering signals that the above
+        * syscalls are intended to block because of the sigmask passed in.
+        */
+-      if (signal_pending(current)) {
++      if (interrupted) {
+               current->saved_sigmask = *sigsaved;
+               set_restore_sigmask();
+               return;