Home Home > GIT Browse
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKernel Build Daemon <kbuild@suse.de>2019-05-02 07:00:25 +0200
committerKernel Build Daemon <kbuild@suse.de>2019-05-02 07:00:25 +0200
commitfefcdd87cf81f45bf4a7fa410fc07837d91c3c12 (patch)
tree9668048b84b31ec3ff92b7e07c246962ca42df4c
parentd079bca3e881fe4c5f27eb4c34bba25630584110 (diff)
parentfd88aa520faf27ce8079ab3fa727679b0c8b6922 (diff)
Merge branch 'SLE15' into SLE12-SP4
-rw-r--r--blacklist.conf2
-rw-r--r--patches.fixes/0001-futex-Cure-exit-race.patch181
-rw-r--r--patches.fixes/kernfs-dont-set-dentry-d_fsdata.patch269
-rw-r--r--series.conf2
4 files changed, 454 insertions, 0 deletions
diff --git a/blacklist.conf b/blacklist.conf
index 735a9b7d90..5987bd0c83 100644
--- a/blacklist.conf
+++ b/blacklist.conf
@@ -1091,3 +1091,5 @@ d6097c9e4454adf1f8f2c9547c2fa6060d55d952 # no difference on !PREEMPT kernel
ec91e78d378cc5d4b43805a1227d8e04e5dfa17d # no bugfix, just cleanup
f880eea68fe593342fa6e09be9bb661f3c297aec # no bugfix, just cleanup
462ce5d963f18b71c63f6b7730a35a2ee5273540 # included in patches.drm/0005-drm-vc4-Fix-memory-leak-during-gpu-reset.patch: drm/vc4: Fix compilation error reported by kbuild test bot
+a9903f04e0a4ea522d959c2f287cdf0ab029e324 # minor debug changes, not needed
+ca66e797120fb09b8138623fb4b563e952586ef5 # breaks kABI
diff --git a/patches.fixes/0001-futex-Cure-exit-race.patch b/patches.fixes/0001-futex-Cure-exit-race.patch
new file mode 100644
index 0000000000..b76a28b1a6
--- /dev/null
+++ b/patches.fixes/0001-futex-Cure-exit-race.patch
@@ -0,0 +1,181 @@
+From abefdef858eb95a5ceb5a594b85a51fcdedad11d Mon Sep 17 00:00:00 2001
+From: Thomas Gleixner <tglx@linutronix.de>
+Date: Wed, 1 May 2019 09:18:02 -0700
+Subject: [PATCH] futex: Cure exit race
+Git-commit: da791a667536bf8322042e38ca85d55a78d3c273
+Patch-mainline: v4.20
+References: bsc#1050549
+
+Stefan reported, that the glibc tst-robustpi4 test case fails
+occasionally. That case creates the following race between
+sys_exit() and sys_futex_lock_pi():
+
+ CPU0 CPU1
+
+ sys_exit() sys_futex()
+ do_exit() futex_lock_pi()
+ exit_signals(tsk) No waiters:
+ tsk->flags |= PF_EXITING; *uaddr == 0x00000PID
+ mm_release(tsk) Set waiter bit
+ exit_robust_list(tsk) { *uaddr = 0x80000PID;
+ Set owner died attach_to_pi_owner() {
+ *uaddr = 0xC0000000; tsk = get_task(PID);
+ } if (!tsk->flags & PF_EXITING) {
+ ... attach();
+ tsk->flags |= PF_EXITPIDONE; } else {
+ if (!(tsk->flags & PF_EXITPIDONE))
+ return -EAGAIN;
+ return -ESRCH; <--- FAIL
+ }
+
+ESRCH is returned all the way to user space, which triggers the glibc test
+case assert. Returning ESRCH unconditionally is wrong here because the user
+space value has been changed by the exiting task to 0xC0000000, i.e. the
+FUTEX_OWNER_DIED bit is set and the futex PID value has been cleared. This
+is a valid state and the kernel has to handle it, i.e. taking the futex.
+
+Cure it by rereading the user space value when PF_EXITING and PF_EXITPIDONE
+is set in the task which 'owns' the futex. If the value has changed, let
+the kernel retry the operation, which includes all regular sanity checks
+and correctly handles the FUTEX_OWNER_DIED case.
+
+If it hasn't changed, then return ESRCH as there is no way to distinguish
+this case from malfunctioning user space. This happens when the exiting
+task did not have a robust list, the robust list was corrupted or the user
+space value in the futex was simply bogus.
+
+Reported-by: Stefan Liebler <stli@linux.ibm.com>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Acked-by: Peter Zijlstra <peterz@infradead.org>
+Cc: Heiko Carstens <heiko.carstens@de.ibm.com>
+Cc: Darren Hart <dvhart@infradead.org>
+Cc: Ingo Molnar <mingo@kernel.org>
+Cc: Sasha Levin <sashal@kernel.org>
+Cc: stable@vger.kernel.org
+Link: https://bugzilla.kernel.org/show_bug.cgi?id=200467
+Link: https://lkml.kernel.org/r/20181210152311.986181245@linutronix.de
+Signed-off-by: Davidlohr Bueso <dbueso@suse.de>
+
+---
+ kernel/futex.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++-----
+ 1 file changed, 63 insertions(+), 6 deletions(-)
+
+diff --git a/kernel/futex.c b/kernel/futex.c
+index 280c148acb2a..42b914d97ba3 100644
+--- a/kernel/futex.c
++++ b/kernel/futex.c
+@@ -1162,11 +1162,65 @@ static int attach_to_pi_state(u32 __user *uaddr, u32 uval,
+ return ret;
+ }
+
++static int handle_exit_race(u32 __user *uaddr, u32 uval,
++ struct task_struct *tsk)
++{
++ u32 uval2;
++
++ /*
++ * If PF_EXITPIDONE is not yet set, then try again.
++ */
++ if (tsk && !(tsk->flags & PF_EXITPIDONE))
++ return -EAGAIN;
++
++ /*
++ * Reread the user space value to handle the following situation:
++ *
++ * CPU0 CPU1
++ *
++ * sys_exit() sys_futex()
++ * do_exit() futex_lock_pi()
++ * futex_lock_pi_atomic()
++ * exit_signals(tsk) No waiters:
++ * tsk->flags |= PF_EXITING; *uaddr == 0x00000PID
++ * mm_release(tsk) Set waiter bit
++ * exit_robust_list(tsk) { *uaddr = 0x80000PID;
++ * Set owner died attach_to_pi_owner() {
++ * *uaddr = 0xC0000000; tsk = get_task(PID);
++ * } if (!tsk->flags & PF_EXITING) {
++ * ... attach();
++ * tsk->flags |= PF_EXITPIDONE; } else {
++ * if (!(tsk->flags & PF_EXITPIDONE))
++ * return -EAGAIN;
++ * return -ESRCH; <--- FAIL
++ * }
++ *
++ * Returning ESRCH unconditionally is wrong here because the
++ * user space value has been changed by the exiting task.
++ *
++ * The same logic applies to the case where the exiting task is
++ * already gone.
++ */
++ if (get_futex_value_locked(&uval2, uaddr))
++ return -EFAULT;
++
++ /* If the user space value has changed, try again. */
++ if (uval2 != uval)
++ return -EAGAIN;
++
++ /*
++ * The exiting task did not have a robust list, the robust list was
++ * corrupted or the user space value in *uaddr is simply bogus.
++ * Give up and tell user space.
++ */
++ return -ESRCH;
++}
++
+ /*
+ * Lookup the task for the TID provided from user space and attach to
+ * it after doing proper sanity checks.
+ */
+-static int attach_to_pi_owner(u32 uval, union futex_key *key,
++static int attach_to_pi_owner(u32 __user *uaddr, u32 uval, union futex_key *key,
+ struct futex_pi_state **ps)
+ {
+ pid_t pid = uval & FUTEX_TID_MASK;
+@@ -1176,12 +1230,15 @@ static int attach_to_pi_owner(u32 uval, union futex_key *key,
+ /*
+ * We are the first waiter - try to look up the real owner and attach
+ * the new pi_state to it, but bail out when TID = 0 [1]
++ *
++ * The !pid check is paranoid. None of the call sites should end up
++ * with pid == 0, but better safe than sorry. Let the caller retry
+ */
+ if (!pid)
+- return -ESRCH;
++ return -EAGAIN;
+ p = futex_find_get_task(pid);
+ if (!p)
+- return -ESRCH;
++ return handle_exit_race(uaddr, uval, NULL);
+
+ if (unlikely(p->flags & PF_KTHREAD)) {
+ put_task_struct(p);
+@@ -1201,7 +1258,7 @@ static int attach_to_pi_owner(u32 uval, union futex_key *key,
+ * set, we know that the task has finished the
+ * cleanup:
+ */
+- int ret = (p->flags & PF_EXITPIDONE) ? -ESRCH : -EAGAIN;
++ int ret = handle_exit_race(uaddr, uval, p);
+
+ raw_spin_unlock_irq(&p->pi_lock);
+ put_task_struct(p);
+@@ -1258,7 +1315,7 @@ static int lookup_pi_state(u32 __user *uaddr, u32 uval,
+ * We are the first waiter - try to look up the owner based on
+ * @uval and attach to it.
+ */
+- return attach_to_pi_owner(uval, key, ps);
++ return attach_to_pi_owner(uaddr, uval, key, ps);
+ }
+
+ static int lock_pi_update_atomic(u32 __user *uaddr, u32 uval, u32 newval)
+@@ -1366,7 +1423,7 @@ static int futex_lock_pi_atomic(u32 __user *uaddr, struct futex_hash_bucket *hb,
+ * attach to the owner. If that fails, no harm done, we only
+ * set the FUTEX_WAITERS bit in the user space variable.
+ */
+- return attach_to_pi_owner(uval, key, ps);
++ return attach_to_pi_owner(uaddr, newval, key, ps);
+ }
+
+ /**
+--
+2.16.4
+
diff --git a/patches.fixes/kernfs-dont-set-dentry-d_fsdata.patch b/patches.fixes/kernfs-dont-set-dentry-d_fsdata.patch
new file mode 100644
index 0000000000..f94da73846
--- /dev/null
+++ b/patches.fixes/kernfs-dont-set-dentry-d_fsdata.patch
@@ -0,0 +1,269 @@
+From 319ba91d352a74acb47678788109a14b9b4dd4c2 Mon Sep 17 00:00:00 2001
+From: Shaohua Li <shli@fb.com>
+Date: Wed Jul 12 11:49:49 2017 -0700
+Subject: [PATCH] kernfs: don't set dentry->d_fsdata
+Git-commit: 319ba91d352a74acb47678788109a14b9b4dd4c2
+References: boo#1133115
+Patch-mainline: v4.14-rc1
+
+When working on adding exportfs operations in kernfs, I found it's hard
+to initialize dentry->d_fsdata in the exportfs operations. Looks there
+is no way to do it without race condition. Look at the kernfs code
+closely, there is no point to set dentry->d_fsdata. inode->i_private
+already points to kernfs_node, and we can get inode from a dentry. So
+this patch just delete the d_fsdata usage.
+
+Acked-by: Tejun Heo <tj@kernel.org>
+Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Shaohua Li <shli@fb.com>
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Acked-by: Goldwyn Rodrigues <rgoldwyn@suse.com>
+
+diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c
+index 7be37c8..b61a7ef 100644
+
+--- a/fs/kernfs/dir.c
++++ b/fs/kernfs/dir.c
+@@ -566,7 +566,7 @@ static int kernfs_dop_revalidate(struct dentry *dentry, unsigned int flags)
+ if (d_really_is_negative(dentry))
+ goto out_bad_unlocked;
+
+- kn = dentry->d_fsdata;
++ kn = kernfs_dentry_node(dentry);
+ mutex_lock(&kernfs_mutex);
+
+ /* The kernfs node has been deactivated */
+@@ -574,7 +574,7 @@ static int kernfs_dop_revalidate(struct dentry *dentry, unsigned int flags)
+ goto out_bad;
+
+ /* The kernfs node has been moved? */
+- if (dentry->d_parent->d_fsdata != kn->parent)
++ if (kernfs_dentry_node(dentry->d_parent) != kn->parent)
+ goto out_bad;
+
+ /* The kernfs node has been renamed */
+@@ -594,14 +594,8 @@ static int kernfs_dop_revalidate(struct dentry *dentry, unsigned int flags)
+ return 0;
+ }
+
+-static void kernfs_dop_release(struct dentry *dentry)
+-{
+- kernfs_put(dentry->d_fsdata);
+-}
+-
+ const struct dentry_operations kernfs_dops = {
+ .d_revalidate = kernfs_dop_revalidate,
+- .d_release = kernfs_dop_release,
+ };
+
+ /**
+@@ -617,8 +611,9 @@ const struct dentry_operations kernfs_dops = {
+ */
+ struct kernfs_node *kernfs_node_from_dentry(struct dentry *dentry)
+ {
+- if (dentry->d_sb->s_op == &kernfs_sops)
+- return dentry->d_fsdata;
++ if (dentry->d_sb->s_op == &kernfs_sops &&
++ !d_really_is_negative(dentry))
++ return kernfs_dentry_node(dentry);
+ return NULL;
+ }
+
+@@ -1056,7 +1051,7 @@ static struct dentry *kernfs_iop_lookup(struct inode *dir,
+ unsigned int flags)
+ {
+ struct dentry *ret;
+- struct kernfs_node *parent = dentry->d_parent->d_fsdata;
++ struct kernfs_node *parent = dir->i_private;
+ struct kernfs_node *kn;
+ struct inode *inode;
+ const void *ns = NULL;
+@@ -1073,8 +1068,6 @@ static struct dentry *kernfs_iop_lookup(struct inode *dir,
+ ret = NULL;
+ goto out_unlock;
+ }
+- kernfs_get(kn);
+- dentry->d_fsdata = kn;
+
+ /* attach dentry and inode */
+ inode = kernfs_get_inode(dir->i_sb, kn);
+@@ -1111,7 +1104,7 @@ static int kernfs_iop_mkdir(struct inode *dir, struct dentry *dentry,
+
+ static int kernfs_iop_rmdir(struct inode *dir, struct dentry *dentry)
+ {
+- struct kernfs_node *kn = dentry->d_fsdata;
++ struct kernfs_node *kn = kernfs_dentry_node(dentry);
+ struct kernfs_syscall_ops *scops = kernfs_root(kn)->syscall_ops;
+ int ret;
+
+@@ -1131,7 +1124,7 @@ static int kernfs_iop_rename(struct inode *old_dir, struct dentry *old_dentry,
+ struct inode *new_dir, struct dentry *new_dentry,
+ unsigned int flags)
+ {
+- struct kernfs_node *kn = old_dentry->d_fsdata;
++ struct kernfs_node *kn = kernfs_dentry_node(old_dentry);
+ struct kernfs_node *new_parent = new_dir->i_private;
+ struct kernfs_syscall_ops *scops = kernfs_root(kn)->syscall_ops;
+ int ret;
+@@ -1644,7 +1637,7 @@ static struct kernfs_node *kernfs_dir_next_pos(const void *ns,
+ static int kernfs_fop_readdir(struct file *file, struct dir_context *ctx)
+ {
+ struct dentry *dentry = file->f_path.dentry;
+- struct kernfs_node *parent = dentry->d_fsdata;
++ struct kernfs_node *parent = kernfs_dentry_node(dentry);
+ struct kernfs_node *pos = file->private_data;
+ const void *ns = NULL;
+
+diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c
+index ac2dfe0..7f90d4d 100644
+--- a/fs/kernfs/file.c
++++ b/fs/kernfs/file.c
+@@ -616,7 +616,7 @@ static void kernfs_put_open_node(struct kernfs_node *kn,
+
+ static int kernfs_fop_open(struct inode *inode, struct file *file)
+ {
+- struct kernfs_node *kn = file->f_path.dentry->d_fsdata;
++ struct kernfs_node *kn = inode->i_private;
+ struct kernfs_root *root = kernfs_root(kn);
+ const struct kernfs_ops *ops;
+ struct kernfs_open_file *of;
+@@ -768,7 +768,7 @@ static void kernfs_release_file(struct kernfs_node *kn,
+
+ static int kernfs_fop_release(struct inode *inode, struct file *filp)
+ {
+- struct kernfs_node *kn = filp->f_path.dentry->d_fsdata;
++ struct kernfs_node *kn = inode->i_private;
+ struct kernfs_open_file *of = kernfs_of(filp);
+
+ if (kn->flags & KERNFS_HAS_RELEASE) {
+@@ -835,7 +835,7 @@ void kernfs_drain_open_files(struct kernfs_node *kn)
+ static unsigned int kernfs_fop_poll(struct file *filp, poll_table *wait)
+ {
+ struct kernfs_open_file *of = kernfs_of(filp);
+- struct kernfs_node *kn = filp->f_path.dentry->d_fsdata;
++ struct kernfs_node *kn = kernfs_dentry_node(filp->f_path.dentry);
+ struct kernfs_open_node *on = kn->attr.open;
+
+ if (!kernfs_get_active(kn))
+diff --git a/fs/kernfs/inode.c b/fs/kernfs/inode.c
+index 79cdae4..4c8b510 100644
+--- a/fs/kernfs/inode.c
++++ b/fs/kernfs/inode.c
+@@ -112,7 +112,7 @@ int kernfs_setattr(struct kernfs_node *kn, const struct iattr *iattr)
+ int kernfs_iop_setattr(struct dentry *dentry, struct iattr *iattr)
+ {
+ struct inode *inode = d_inode(dentry);
+- struct kernfs_node *kn = dentry->d_fsdata;
++ struct kernfs_node *kn = inode->i_private;
+ int error;
+
+ if (!kn)
+@@ -154,7 +154,7 @@ static int kernfs_node_setsecdata(struct kernfs_iattrs *attrs, void **secdata,
+
+ ssize_t kernfs_iop_listxattr(struct dentry *dentry, char *buf, size_t size)
+ {
+- struct kernfs_node *kn = dentry->d_fsdata;
++ struct kernfs_node *kn = kernfs_dentry_node(dentry);
+ struct kernfs_iattrs *attrs;
+
+ attrs = kernfs_iattrs(kn);
+@@ -203,8 +203,8 @@ static void kernfs_refresh_inode(struct kernfs_node *kn, struct inode *inode)
+ int kernfs_iop_getattr(const struct path *path, struct kstat *stat,
+ u32 request_mask, unsigned int query_flags)
+ {
+- struct kernfs_node *kn = path->dentry->d_fsdata;
+ struct inode *inode = d_inode(path->dentry);
++ struct kernfs_node *kn = inode->i_private;
+
+ mutex_lock(&kernfs_mutex);
+ kernfs_refresh_inode(kn, inode);
+diff --git a/fs/kernfs/kernfs-internal.h b/fs/kernfs/kernfs-internal.h
+index e9c226f..0f260dc 100644
+--- a/fs/kernfs/kernfs-internal.h
++++ b/fs/kernfs/kernfs-internal.h
+@@ -70,6 +70,13 @@ struct kernfs_super_info {
+ };
+ #define kernfs_info(SB) ((struct kernfs_super_info *)(SB->s_fs_info))
+
++static inline struct kernfs_node *kernfs_dentry_node(struct dentry *dentry)
++{
++ if (d_really_is_negative(dentry))
++ return NULL;
++ return d_inode(dentry)->i_private;
++}
++
+ extern const struct super_operations kernfs_sops;
+ extern struct kmem_cache *kernfs_node_cache;
+
+diff --git a/fs/kernfs/mount.c b/fs/kernfs/mount.c
+index 69c48be..acd5426 100644
+--- a/fs/kernfs/mount.c
++++ b/fs/kernfs/mount.c
+@@ -33,7 +33,7 @@ static int kernfs_sop_remount_fs(struct super_block *sb, int *flags, char *data)
+
+ static int kernfs_sop_show_options(struct seq_file *sf, struct dentry *dentry)
+ {
+- struct kernfs_root *root = kernfs_root(dentry->d_fsdata);
++ struct kernfs_root *root = kernfs_root(kernfs_dentry_node(dentry));
+ struct kernfs_syscall_ops *scops = root->syscall_ops;
+
+ if (scops && scops->show_options)
+@@ -43,7 +43,7 @@ static int kernfs_sop_show_options(struct seq_file *sf, struct dentry *dentry)
+
+ static int kernfs_sop_show_path(struct seq_file *sf, struct dentry *dentry)
+ {
+- struct kernfs_node *node = dentry->d_fsdata;
++ struct kernfs_node *node = kernfs_dentry_node(dentry);
+ struct kernfs_root *root = kernfs_root(node);
+ struct kernfs_syscall_ops *scops = root->syscall_ops;
+
+@@ -176,8 +176,6 @@ static int kernfs_fill_super(struct super_block *sb, unsigned long magic)
+ pr_debug("%s: could not get root dentry!\n", __func__);
+ return -ENOMEM;
+ }
+- kernfs_get(info->root->kn);
+- root->d_fsdata = info->root->kn;
+ sb->s_root = root;
+ sb->s_d_op = &kernfs_dops;
+ return 0;
+@@ -283,7 +281,6 @@ struct dentry *kernfs_mount_ns(struct file_system_type *fs_type, int flags,
+ void kernfs_kill_sb(struct super_block *sb)
+ {
+ struct kernfs_super_info *info = kernfs_info(sb);
+- struct kernfs_node *root_kn = sb->s_root->d_fsdata;
+
+ mutex_lock(&kernfs_mutex);
+ list_del(&info->node);
+@@ -295,7 +292,6 @@ void kernfs_kill_sb(struct super_block *sb)
+ */
+ kill_anon_super(sb);
+ kfree(info);
+- kernfs_put(root_kn);
+ }
+
+ /**
+diff --git a/fs/kernfs/symlink.c b/fs/kernfs/symlink.c
+index 1684af4..08ccabd 100644
+--- a/fs/kernfs/symlink.c
++++ b/fs/kernfs/symlink.c
+@@ -98,9 +98,9 @@ static int kernfs_get_target_path(struct kernfs_node *parent,
+ return 0;
+ }
+
+-static int kernfs_getlink(struct dentry *dentry, char *path)
++static int kernfs_getlink(struct inode *inode, char *path)
+ {
+- struct kernfs_node *kn = dentry->d_fsdata;
++ struct kernfs_node *kn = inode->i_private;
+ struct kernfs_node *parent = kn->parent;
+ struct kernfs_node *target = kn->symlink.target_kn;
+ int error;
+@@ -124,7 +124,7 @@ static const char *kernfs_iop_get_link(struct dentry *dentry,
+ body = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!body)
+ return ERR_PTR(-ENOMEM);
+- error = kernfs_getlink(dentry, body);
++ error = kernfs_getlink(inode, body);
+ if (unlikely(error < 0)) {
+ kfree(body);
+ return ERR_PTR(error);
diff --git a/series.conf b/series.conf
index 68863e9ea8..72d208685a 100644
--- a/series.conf
+++ b/series.conf
@@ -6225,6 +6225,7 @@
patches.arch/powerpc-xive-15-improve-debugging-macros.patch
patches.arch/powerpc-xive-16-Fix-section-__init-warning.patch
patches.fixes/xen-events-fifo-dont-use-get-put-cpu.patch
+ patches.fixes/kernfs-dont-set-dentry-d_fsdata.patch
patches.suse/0003-block-Add-comment-to-submit_bio_wait.patch
patches.suse/0004-bio-integrity-move-the-bio-integrity-profile-check-e.patch
patches.suse/0005-dm-crypt-don-t-mess-with-BIP_BLOCK_INTEGRITY.patch
@@ -20464,6 +20465,7 @@
patches.drm/0001-drm-ioctl-Fix-Spectre-v1-vulnerabilities.patch
patches.fixes/x86-mm-Fix-decoy-address-handling-vs-32-bit-builds.patch
patches.arch/x86-mtrr-don-t-copy-uninitialized-gentry-fields-back-to-userspace.patch
+ patches.fixes/0001-futex-Cure-exit-race.patch
patches.suse/tcp-fix-a-race-in-inet_diag_dump_icsk.patch
patches.suse/packet-validate-address-length.patch
patches.suse/ipv6-tunnels-fix-two-use-after-free.patch