diff options
author | Justin M. Forbes <jforbes@fedoraproject.org> | 2018-07-05 09:31:36 -0500 |
---|---|---|
committer | Justin M. Forbes <jforbes@fedoraproject.org> | 2018-07-05 09:31:36 -0500 |
commit | 1a9181ff17aa8e6c755e8e9f49b6a3b840c8ce8f (patch) | |
tree | 6c6a6fead0f2449d832dfaeb786f305db7413f4d | |
parent | 539a3afe2de9751709aaa31c8475b5128d923ee4 (diff) | |
download | kernel-1a9181ff17aa8e6c755e8e9f49b6a3b840c8ce8f.tar.gz kernel-1a9181ff17aa8e6c755e8e9f49b6a3b840c8ce8f.tar.xz kernel-1a9181ff17aa8e6c755e8e9f49b6a3b840c8ce8f.zip |
Fix CVE-2018-13053 CVE-2018-12896 CVE-2018-13093 CVE-2018-13094 CVE-2018-13095
-rw-r--r-- | 0001-xfs-More-robust-inode-extent-count-validation.patch | 141 | ||||
-rw-r--r-- | 0001-xfs-don-t-call-xfs_da_shrink_inode-with-NULL-bp.patch | 43 | ||||
-rw-r--r-- | 0001-xfs-validate-cached-inodes-are-free-when-allocated.patch | 155 | ||||
-rw-r--r-- | 1-2-posix-timers-Make-forward-callback-return-s64.patch | 86 | ||||
-rw-r--r-- | 2-2-posix-timers-Sanitize-overrun-handling.patch | 145 | ||||
-rw-r--r-- | alarmtimer-prevent-overflow-for-relative-nanosleep.patch | 50 | ||||
-rw-r--r-- | kernel.spec | 23 |
7 files changed, 643 insertions, 0 deletions
diff --git a/0001-xfs-More-robust-inode-extent-count-validation.patch b/0001-xfs-More-robust-inode-extent-count-validation.patch new file mode 100644 index 000000000..767eb6fac --- /dev/null +++ b/0001-xfs-More-robust-inode-extent-count-validation.patch @@ -0,0 +1,141 @@ +From 23fcb3340d033d9f081e21e6c12c2db7eaa541d3 Mon Sep 17 00:00:00 2001 +From: Dave Chinner <dchinner@redhat.com> +Date: Thu, 21 Jun 2018 23:25:57 -0700 +Subject: [PATCH] xfs: More robust inode extent count validation + +When the inode is in extent format, it can't have more extents that +fit in the inode fork. We don't currenty check this, and so this +corruption goes unnoticed by the inode verifiers. This can lead to +crashes operating on invalid in-memory structures. + +Attempts to access such a inode will now error out in the verifier +rather than allowing modification operations to proceed. + +Reported-by: Wen Xu <wen.xu@gatech.edu> +Signed-off-by: Dave Chinner <dchinner@redhat.com> +Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com> +[darrick: fix a typedef, add some braces and breaks to shut up compiler warnings] +Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> +--- + fs/xfs/libxfs/xfs_format.h | 3 ++ + fs/xfs/libxfs/xfs_inode_buf.c | 76 ++++++++++++++++++++++------------- + 2 files changed, 50 insertions(+), 29 deletions(-) + +diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h +index 1c5a8aaf2bfc..7b4a43deb83e 100644 +--- a/fs/xfs/libxfs/xfs_format.h ++++ b/fs/xfs/libxfs/xfs_format.h +@@ -962,6 +962,9 @@ typedef enum xfs_dinode_fmt { + XFS_DFORK_DSIZE(dip, mp) : \ + XFS_DFORK_ASIZE(dip, mp)) + ++#define XFS_DFORK_MAXEXT(dip, mp, w) \ ++ (XFS_DFORK_SIZE(dip, mp, w) / sizeof(struct xfs_bmbt_rec)) ++ + /* + * Return pointers to the data or attribute forks. + */ +diff --git a/fs/xfs/libxfs/xfs_inode_buf.c b/fs/xfs/libxfs/xfs_inode_buf.c +index d38d724534c4..33dc34655ac3 100644 +--- a/fs/xfs/libxfs/xfs_inode_buf.c ++++ b/fs/xfs/libxfs/xfs_inode_buf.c +@@ -374,6 +374,47 @@ xfs_log_dinode_to_disk( + } + } + ++static xfs_failaddr_t ++xfs_dinode_verify_fork( ++ struct xfs_dinode *dip, ++ struct xfs_mount *mp, ++ int whichfork) ++{ ++ uint32_t di_nextents = XFS_DFORK_NEXTENTS(dip, whichfork); ++ ++ switch (XFS_DFORK_FORMAT(dip, whichfork)) { ++ case XFS_DINODE_FMT_LOCAL: ++ /* ++ * no local regular files yet ++ */ ++ if (whichfork == XFS_DATA_FORK) { ++ if (S_ISREG(be16_to_cpu(dip->di_mode))) ++ return __this_address; ++ if (be64_to_cpu(dip->di_size) > ++ XFS_DFORK_SIZE(dip, mp, whichfork)) ++ return __this_address; ++ } ++ if (di_nextents) ++ return __this_address; ++ break; ++ case XFS_DINODE_FMT_EXTENTS: ++ if (di_nextents > XFS_DFORK_MAXEXT(dip, mp, whichfork)) ++ return __this_address; ++ break; ++ case XFS_DINODE_FMT_BTREE: ++ if (whichfork == XFS_ATTR_FORK) { ++ if (di_nextents > MAXAEXTNUM) ++ return __this_address; ++ } else if (di_nextents > MAXEXTNUM) { ++ return __this_address; ++ } ++ break; ++ default: ++ return __this_address; ++ } ++ return NULL; ++} ++ + xfs_failaddr_t + xfs_dinode_verify( + struct xfs_mount *mp, +@@ -441,24 +482,9 @@ xfs_dinode_verify( + case S_IFREG: + case S_IFLNK: + case S_IFDIR: +- switch (dip->di_format) { +- case XFS_DINODE_FMT_LOCAL: +- /* +- * no local regular files yet +- */ +- if (S_ISREG(mode)) +- return __this_address; +- if (di_size > XFS_DFORK_DSIZE(dip, mp)) +- return __this_address; +- if (dip->di_nextents) +- return __this_address; +- /* fall through */ +- case XFS_DINODE_FMT_EXTENTS: +- case XFS_DINODE_FMT_BTREE: +- break; +- default: +- return __this_address; +- } ++ fa = xfs_dinode_verify_fork(dip, mp, XFS_DATA_FORK); ++ if (fa) ++ return fa; + break; + case 0: + /* Uninitialized inode ok. */ +@@ -468,17 +494,9 @@ xfs_dinode_verify( + } + + if (XFS_DFORK_Q(dip)) { +- switch (dip->di_aformat) { +- case XFS_DINODE_FMT_LOCAL: +- if (dip->di_anextents) +- return __this_address; +- /* fall through */ +- case XFS_DINODE_FMT_EXTENTS: +- case XFS_DINODE_FMT_BTREE: +- break; +- default: +- return __this_address; +- } ++ fa = xfs_dinode_verify_fork(dip, mp, XFS_ATTR_FORK); ++ if (fa) ++ return fa; + } else { + /* + * If there is no fork offset, this may be a freshly-made inode +-- +2.17.1 + diff --git a/0001-xfs-don-t-call-xfs_da_shrink_inode-with-NULL-bp.patch b/0001-xfs-don-t-call-xfs_da_shrink_inode-with-NULL-bp.patch new file mode 100644 index 000000000..874536f24 --- /dev/null +++ b/0001-xfs-don-t-call-xfs_da_shrink_inode-with-NULL-bp.patch @@ -0,0 +1,43 @@ +From bb3d48dcf86a97dc25fe9fc2c11938e19cb4399a Mon Sep 17 00:00:00 2001 +From: Eric Sandeen <sandeen@sandeen.net> +Date: Fri, 8 Jun 2018 09:53:49 -0700 +Subject: [PATCH] xfs: don't call xfs_da_shrink_inode with NULL bp + +xfs_attr3_leaf_create may have errored out before instantiating a buffer, +for example if the blkno is out of range. In that case there is no work +to do to remove it, and in fact xfs_da_shrink_inode will lead to an oops +if we try. + +This also seems to fix a flaw where the original error from +xfs_attr3_leaf_create gets overwritten in the cleanup case, and it +removes a pointless assignment to bp which isn't used after this. + +Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=199969 +Reported-by: Xu, Wen <wen.xu@gatech.edu> +Tested-by: Xu, Wen <wen.xu@gatech.edu> +Signed-off-by: Eric Sandeen <sandeen@redhat.com> +Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com> +Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> +--- + fs/xfs/libxfs/xfs_attr_leaf.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c +index 99e0f5749dba..76e90046731c 100644 +--- a/fs/xfs/libxfs/xfs_attr_leaf.c ++++ b/fs/xfs/libxfs/xfs_attr_leaf.c +@@ -791,9 +791,8 @@ xfs_attr_shortform_to_leaf( + ASSERT(blkno == 0); + error = xfs_attr3_leaf_create(args, blkno, &bp); + if (error) { +- error = xfs_da_shrink_inode(args, 0, bp); +- bp = NULL; +- if (error) ++ /* xfs_attr3_leaf_create may not have instantiated a block */ ++ if (bp && (xfs_da_shrink_inode(args, 0, bp) != 0)) + goto out; + xfs_idata_realloc(dp, size, XFS_ATTR_FORK); /* try to put */ + memcpy(ifp->if_u1.if_data, tmpbuffer, size); /* it back */ +-- +2.17.1 + diff --git a/0001-xfs-validate-cached-inodes-are-free-when-allocated.patch b/0001-xfs-validate-cached-inodes-are-free-when-allocated.patch new file mode 100644 index 000000000..ce78bed80 --- /dev/null +++ b/0001-xfs-validate-cached-inodes-are-free-when-allocated.patch @@ -0,0 +1,155 @@ +From afca6c5b2595fc44383919fba740c194b0b76aff Mon Sep 17 00:00:00 2001 +From: Dave Chinner <dchinner@redhat.com> +Date: Tue, 17 Apr 2018 17:17:34 -0700 +Subject: [PATCH] xfs: validate cached inodes are free when allocated + +A recent fuzzed filesystem image cached random dcache corruption +when the reproducer was run. This often showed up as panics in +lookup_slow() on a null inode->i_ops pointer when doing pathwalks. + +BUG: unable to handle kernel NULL pointer dereference at 0000000000000000 +.... +Call Trace: + lookup_slow+0x44/0x60 + walk_component+0x3dd/0x9f0 + link_path_walk+0x4a7/0x830 + path_lookupat+0xc1/0x470 + filename_lookup+0x129/0x270 + user_path_at_empty+0x36/0x40 + path_listxattr+0x98/0x110 + SyS_listxattr+0x13/0x20 + do_syscall_64+0xf5/0x280 + entry_SYSCALL_64_after_hwframe+0x42/0xb7 + +but had many different failure modes including deadlocks trying to +lock the inode that was just allocated or KASAN reports of +use-after-free violations. + +The cause of the problem was a corrupt INOBT on a v4 fs where the +root inode was marked as free in the inobt record. Hence when we +allocated an inode, it chose the root inode to allocate, found it in +the cache and re-initialised it. + +We recently fixed a similar inode allocation issue caused by inobt +record corruption problem in xfs_iget_cache_miss() in commit +ee457001ed6c ("xfs: catch inode allocation state mismatch +corruption"). This change adds similar checks to the cache-hit path +to catch it, and turns the reproducer into a corruption shutdown +situation. + +Reported-by: Wen Xu <wen.xu@gatech.edu> +Signed-Off-By: Dave Chinner <dchinner@redhat.com> +Reviewed-by: Christoph Hellwig <hch@lst.de> +Reviewed-by: Carlos Maiolino <cmaiolino@redhat.com> +Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com> +[darrick: fix typos in comment] +Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> +--- + fs/xfs/xfs_icache.c | 73 +++++++++++++++++++++++++++++---------------- + 1 file changed, 48 insertions(+), 25 deletions(-) + +diff --git a/fs/xfs/xfs_icache.c b/fs/xfs/xfs_icache.c +index 9a18f69f6e96..817899961f48 100644 +--- a/fs/xfs/xfs_icache.c ++++ b/fs/xfs/xfs_icache.c +@@ -308,6 +308,46 @@ xfs_reinit_inode( + return error; + } + ++/* ++ * If we are allocating a new inode, then check what was returned is ++ * actually a free, empty inode. If we are not allocating an inode, ++ * then check we didn't find a free inode. ++ * ++ * Returns: ++ * 0 if the inode free state matches the lookup context ++ * -ENOENT if the inode is free and we are not allocating ++ * -EFSCORRUPTED if there is any state mismatch at all ++ */ ++static int ++xfs_iget_check_free_state( ++ struct xfs_inode *ip, ++ int flags) ++{ ++ if (flags & XFS_IGET_CREATE) { ++ /* should be a free inode */ ++ if (VFS_I(ip)->i_mode != 0) { ++ xfs_warn(ip->i_mount, ++"Corruption detected! Free inode 0x%llx not marked free! (mode 0x%x)", ++ ip->i_ino, VFS_I(ip)->i_mode); ++ return -EFSCORRUPTED; ++ } ++ ++ if (ip->i_d.di_nblocks != 0) { ++ xfs_warn(ip->i_mount, ++"Corruption detected! Free inode 0x%llx has blocks allocated!", ++ ip->i_ino); ++ return -EFSCORRUPTED; ++ } ++ return 0; ++ } ++ ++ /* should be an allocated inode */ ++ if (VFS_I(ip)->i_mode == 0) ++ return -ENOENT; ++ ++ return 0; ++} ++ + /* + * Check the validity of the inode we just found it the cache + */ +@@ -357,12 +397,12 @@ xfs_iget_cache_hit( + } + + /* +- * If lookup is racing with unlink return an error immediately. ++ * Check the inode free state is valid. This also detects lookup ++ * racing with unlinks. + */ +- if (VFS_I(ip)->i_mode == 0 && !(flags & XFS_IGET_CREATE)) { +- error = -ENOENT; ++ error = xfs_iget_check_free_state(ip, flags); ++ if (error) + goto out_error; +- } + + /* + * If IRECLAIMABLE is set, we've torn down the VFS inode already. +@@ -485,29 +525,12 @@ xfs_iget_cache_miss( + + + /* +- * If we are allocating a new inode, then check what was returned is +- * actually a free, empty inode. If we are not allocating an inode, +- * the check we didn't find a free inode. ++ * Check the inode free state is valid. This also detects lookup ++ * racing with unlinks. + */ +- if (flags & XFS_IGET_CREATE) { +- if (VFS_I(ip)->i_mode != 0) { +- xfs_warn(mp, +-"Corruption detected! Free inode 0x%llx not marked free on disk", +- ino); +- error = -EFSCORRUPTED; +- goto out_destroy; +- } +- if (ip->i_d.di_nblocks != 0) { +- xfs_warn(mp, +-"Corruption detected! Free inode 0x%llx has blocks allocated!", +- ino); +- error = -EFSCORRUPTED; +- goto out_destroy; +- } +- } else if (VFS_I(ip)->i_mode == 0) { +- error = -ENOENT; ++ error = xfs_iget_check_free_state(ip, flags); ++ if (error) + goto out_destroy; +- } + + /* + * Preload the radix tree so we can insert safely under the +-- +2.17.1 + diff --git a/1-2-posix-timers-Make-forward-callback-return-s64.patch b/1-2-posix-timers-Make-forward-callback-return-s64.patch new file mode 100644 index 000000000..3c48968e8 --- /dev/null +++ b/1-2-posix-timers-Make-forward-callback-return-s64.patch @@ -0,0 +1,86 @@ +From patchwork Tue Jun 26 13:21:31 2018 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [1/2] posix-timers: Make forward callback return s64 +From: Thomas Gleixner <tglx@linutronix.de> +X-Patchwork-Id: 10489059 +Message-Id: <20180626132704.922098090@linutronix.de> +To: LKML <linux-kernel@vger.kernel.org> +Cc: John Stultz <john.stultz@linaro.org>, + Peter Zijlstra <peterz@infradead.org>, + Michael Kerrisk <mtk.manpages@gmail.com>, air icy <icytxw@gmail.com> +Date: Tue, 26 Jun 2018 15:21:31 +0200 + +The posix timer ti_overrun handling is broken because the forwarding +functions can return a huge number of overruns which does not fit in an +int. As a consequence timer_getoverrun(2) and siginfo::si_overrun can turn +into random number generators. + +As a first step to address that let the timer_forward() callbacks return +the full 64 bit value. + +Cast it to (int) temporarily until k_itimer::ti_overrun is converted to +64bit and the conversion to user space visible values is sanitized. + +Reported-by: air icy <icytxw@gmail.com> +Signed-off-by: Thomas Gleixner <tglx@linutronix.de> +Acked-by: John Stultz <john.stultz@linaro.org> +--- + kernel/time/alarmtimer.c | 4 ++-- + kernel/time/posix-timers.c | 6 +++--- + kernel/time/posix-timers.h | 2 +- + 3 files changed, 6 insertions(+), 6 deletions(-) + +--- a/kernel/time/alarmtimer.c ++++ b/kernel/time/alarmtimer.c +@@ -581,11 +581,11 @@ static void alarm_timer_rearm(struct k_i + * @timr: Pointer to the posixtimer data struct + * @now: Current time to forward the timer against + */ +-static int alarm_timer_forward(struct k_itimer *timr, ktime_t now) ++static s64 alarm_timer_forward(struct k_itimer *timr, ktime_t now) + { + struct alarm *alarm = &timr->it.alarm.alarmtimer; + +- return (int) alarm_forward(alarm, timr->it_interval, now); ++ return alarm_forward(alarm, timr->it_interval, now); + } + + /** +--- a/kernel/time/posix-timers.c ++++ b/kernel/time/posix-timers.c +@@ -645,11 +645,11 @@ static ktime_t common_hrtimer_remaining( + return __hrtimer_expires_remaining_adjusted(timer, now); + } + +-static int common_hrtimer_forward(struct k_itimer *timr, ktime_t now) ++static s64 common_hrtimer_forward(struct k_itimer *timr, ktime_t now) + { + struct hrtimer *timer = &timr->it.real.timer; + +- return (int)hrtimer_forward(timer, now, timr->it_interval); ++ return hrtimer_forward(timer, now, timr->it_interval); + } + + /* +@@ -702,7 +702,7 @@ void common_timer_get(struct k_itimer *t + * expiry time forward by intervals, so expiry is > now. + */ + if (iv && (timr->it_requeue_pending & REQUEUE_PENDING || sig_none)) +- timr->it_overrun += kc->timer_forward(timr, now); ++ timr->it_overrun += (int)kc->timer_forward(timr, now); + + remaining = kc->timer_remaining(timr, now); + /* Return 0 only, when the timer is expired and not pending */ +--- a/kernel/time/posix-timers.h ++++ b/kernel/time/posix-timers.h +@@ -19,7 +19,7 @@ struct k_clock { + void (*timer_get)(struct k_itimer *timr, + struct itimerspec64 *cur_setting); + void (*timer_rearm)(struct k_itimer *timr); +- int (*timer_forward)(struct k_itimer *timr, ktime_t now); ++ s64 (*timer_forward)(struct k_itimer *timr, ktime_t now); + ktime_t (*timer_remaining)(struct k_itimer *timr, ktime_t now); + int (*timer_try_to_cancel)(struct k_itimer *timr); + void (*timer_arm)(struct k_itimer *timr, ktime_t expires, diff --git a/2-2-posix-timers-Sanitize-overrun-handling.patch b/2-2-posix-timers-Sanitize-overrun-handling.patch new file mode 100644 index 000000000..4132125aa --- /dev/null +++ b/2-2-posix-timers-Sanitize-overrun-handling.patch @@ -0,0 +1,145 @@ +From patchwork Tue Jun 26 13:21:32 2018 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [2/2] posix-timers: Sanitize overrun handling +From: Thomas Gleixner <tglx@linutronix.de> +X-Patchwork-Id: 10489053 +Message-Id: <20180626132705.018623573@linutronix.de> +To: LKML <linux-kernel@vger.kernel.org> +Cc: John Stultz <john.stultz@linaro.org>, + Peter Zijlstra <peterz@infradead.org>, + Michael Kerrisk <mtk.manpages@gmail.com>, air icy <icytxw@gmail.com> +Date: Tue, 26 Jun 2018 15:21:32 +0200 + +The posix timer overrun handling is broken because the forwarding functions +can return a huge number of overruns which does not fit in an int. As a +consequence timer_getoverrun(2) and siginfo::si_overrun can turn into +random number generators. + +The k_clock::timer_forward() callbacks return a 64 bit value now. Make +k_itimer::ti_overrun[_last] 64bit as well, so the kernel internal +accounting is correct. 3Remove the temporary (int) casts. + +Add a helper function which clamps the overrun value returned to user space +via timer_getoverrun(2) or siginfo::si_overrun limited to a positive value +between 0 and INT_MAX. INT_MAX is an indicator for user space that the +overrun value has been clamped. + +Reported-by: air icy <icytxw@gmail.com> +Signed-off-by: Thomas Gleixner <tglx@linutronix.de> +Acked-by: John Stultz <john.stultz@linaro.org> +--- + include/linux/posix-timers.h | 4 ++-- + kernel/time/posix-cpu-timers.c | 2 +- + kernel/time/posix-timers.c | 31 ++++++++++++++++++++----------- + 3 files changed, 23 insertions(+), 14 deletions(-) + +--- a/include/linux/posix-timers.h ++++ b/include/linux/posix-timers.h +@@ -95,8 +95,8 @@ struct k_itimer { + clockid_t it_clock; + timer_t it_id; + int it_active; +- int it_overrun; +- int it_overrun_last; ++ s64 it_overrun; ++ s64 it_overrun_last; + int it_requeue_pending; + int it_sigev_notify; + ktime_t it_interval; +--- a/kernel/time/posix-cpu-timers.c ++++ b/kernel/time/posix-cpu-timers.c +@@ -85,7 +85,7 @@ static void bump_cpu_timer(struct k_itim + continue; + + timer->it.cpu.expires += incr; +- timer->it_overrun += 1 << i; ++ timer->it_overrun += 1LL << i; + delta -= incr; + } + } +--- a/kernel/time/posix-timers.c ++++ b/kernel/time/posix-timers.c +@@ -283,6 +283,17 @@ static __init int init_posix_timers(void + } + __initcall(init_posix_timers); + ++/* ++ * The siginfo si_overrun field and the return value of timer_getoverrun(2) ++ * are of type int. Clamp the overrun value to INT_MAX ++ */ ++static inline int timer_overrun_to_int(struct k_itimer *timr, int baseval) ++{ ++ s64 sum = timr->it_overrun_last + (s64)baseval; ++ ++ return sum > (s64)INT_MAX ? INT_MAX : (int)sum; ++} ++ + static void common_hrtimer_rearm(struct k_itimer *timr) + { + struct hrtimer *timer = &timr->it.real.timer; +@@ -290,9 +301,8 @@ static void common_hrtimer_rearm(struct + if (!timr->it_interval) + return; + +- timr->it_overrun += (unsigned int) hrtimer_forward(timer, +- timer->base->get_time(), +- timr->it_interval); ++ timr->it_overrun += hrtimer_forward(timer, timer->base->get_time(), ++ timr->it_interval); + hrtimer_restart(timer); + } + +@@ -321,10 +331,10 @@ void posixtimer_rearm(struct siginfo *in + + timr->it_active = 1; + timr->it_overrun_last = timr->it_overrun; +- timr->it_overrun = -1; ++ timr->it_overrun = -1LL; + ++timr->it_requeue_pending; + +- info->si_overrun += timr->it_overrun_last; ++ info->si_overrun = timer_overrun_to_int(timr, info->si_overrun); + } + + unlock_timer(timr, flags); +@@ -418,9 +428,8 @@ static enum hrtimer_restart posix_timer_ + now = ktime_add(now, kj); + } + #endif +- timr->it_overrun += (unsigned int) +- hrtimer_forward(timer, now, +- timr->it_interval); ++ timr->it_overrun += hrtimer_forward(timer, now, ++ timr->it_interval); + ret = HRTIMER_RESTART; + ++timr->it_requeue_pending; + timr->it_active = 1; +@@ -524,7 +533,7 @@ static int do_timer_create(clockid_t whi + new_timer->it_id = (timer_t) new_timer_id; + new_timer->it_clock = which_clock; + new_timer->kclock = kc; +- new_timer->it_overrun = -1; ++ new_timer->it_overrun = -1LL; + + if (event) { + rcu_read_lock(); +@@ -702,7 +711,7 @@ void common_timer_get(struct k_itimer *t + * expiry time forward by intervals, so expiry is > now. + */ + if (iv && (timr->it_requeue_pending & REQUEUE_PENDING || sig_none)) +- timr->it_overrun += (int)kc->timer_forward(timr, now); ++ timr->it_overrun += kc->timer_forward(timr, now); + + remaining = kc->timer_remaining(timr, now); + /* Return 0 only, when the timer is expired and not pending */ +@@ -791,7 +800,7 @@ SYSCALL_DEFINE1(timer_getoverrun, timer_ + if (!timr) + return -EINVAL; + +- overrun = timr->it_overrun_last; ++ overrun = timer_overrun_to_int(timr, 0); + unlock_timer(timr, flags); + + return overrun; diff --git a/alarmtimer-prevent-overflow-for-relative-nanosleep.patch b/alarmtimer-prevent-overflow-for-relative-nanosleep.patch new file mode 100644 index 000000000..1ef0e5ab3 --- /dev/null +++ b/alarmtimer-prevent-overflow-for-relative-nanosleep.patch @@ -0,0 +1,50 @@ +From 5f936e19cc0ef97dbe3a56e9498922ad5ba1edef Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner <tglx@linutronix.de> +Date: Mon, 2 Jul 2018 09:34:29 +0200 +Subject: alarmtimer: Prevent overflow for relative nanosleep + +Air Icy reported: + + UBSAN: Undefined behaviour in kernel/time/alarmtimer.c:811:7 + signed integer overflow: + 1529859276030040771 + 9223372036854775807 cannot be represented in type 'long long int' + Call Trace: + alarm_timer_nsleep+0x44c/0x510 kernel/time/alarmtimer.c:811 + __do_sys_clock_nanosleep kernel/time/posix-timers.c:1235 [inline] + __se_sys_clock_nanosleep kernel/time/posix-timers.c:1213 [inline] + __x64_sys_clock_nanosleep+0x326/0x4e0 kernel/time/posix-timers.c:1213 + do_syscall_64+0xb8/0x3a0 arch/x86/entry/common.c:290 + +alarm_timer_nsleep() uses ktime_add() to add the current time and the +relative expiry value. ktime_add() has no sanity checks so the addition +can overflow when the relative timeout is large enough. + +Use ktime_add_safe() which has the necessary sanity checks in place and +limits the result to the valid range. + +Fixes: 9a7adcf5c6de ("timers: Posix interface for alarm-timers") +Reported-by: Team OWL337 <icytxw@gmail.com> +Signed-off-by: Thomas Gleixner <tglx@linutronix.de> +Cc: John Stultz <john.stultz@linaro.org> +Link: https://lkml.kernel.org/r/alpine.DEB.2.21.1807020926360.1595@nanos.tec.linutronix.de +--- + kernel/time/alarmtimer.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c +index 78a3cc5..fa5de5e 100644 +--- a/kernel/time/alarmtimer.c ++++ b/kernel/time/alarmtimer.c +@@ -808,7 +808,8 @@ static int alarm_timer_nsleep(const clockid_t which_clock, int flags, + /* Convert (if necessary) to absolute time */ + if (flags != TIMER_ABSTIME) { + ktime_t now = alarm_bases[type].gettime(); +- exp = ktime_add(now, exp); ++ ++ exp = ktime_add_safe(now, exp); + } + + ret = alarmtimer_do_nsleep(&alarm, exp, type); +-- +cgit v1.1 + diff --git a/kernel.spec b/kernel.spec index d80833b6d..93cdd61ca 100644 --- a/kernel.spec +++ b/kernel.spec @@ -649,6 +649,22 @@ Patch515: 0001-signal-Stop-special-casing-TRAP_FIXME-and-FPE_FIXME-.patch # rhbz 1572944 Patch517: Revert-the-random-series-for-4.16.4.patch +# CVE-2018-13053 rhbz 1597747 1597748 +Patch518: alarmtimer-prevent-overflow-for-relative-nanosleep.patch + +# CVE-2018-12896 rhbz 1597759 1597760 +Patch519: 1-2-posix-timers-Make-forward-callback-return-s64.patch +Patch520: 2-2-posix-timers-Sanitize-overrun-handling.patch + +# CVE-2018-13093 rhbz 1597766 1597767 +Patch521: 0001-xfs-validate-cached-inodes-are-free-when-allocated.patch + +# CVE-2018-13094 rhbz 1597771 1597772 +Patch522: 0001-xfs-don-t-call-xfs_da_shrink_inode-with-NULL-bp.patch + +# CVE-2018-13095 rhbz 1597775 1597777 +Patch523: 0001-xfs-More-robust-inode-extent-count-validation.patch + # END OF PATCH DEFINITIONS %endif @@ -1898,6 +1914,13 @@ fi # # %changelog +* Thu Jul 05 2018 Justin M. Forbes <jforbes@fedoraproject.org> +- Fix CVE-2018-13053 (rhbz 1597747 1597748) +- Fix CVE-2018-12896 (rhbz 1597759 1597760) +- Fix CVE-2018-13093 (rhbz 1597766 1597767) +- Fix CVE-2018-13094 (rhbz 1597771 1597772) +- Fix CVE-2018-13095 (rhbz 1597775 1597777) + * Tue Jul 03 2018 Justin M. Forbes <jforbes@fedoraproject.org> - 4.17.4-100 - Linux v4.17.4 |