Skip to content

Commit

Permalink
Merge branch 'locking-core-for-linus' of git://git.kernel.org/pub/scm…
Browse files Browse the repository at this point in the history
…/linux/kernel/git/tip/tip

Pull locking updates from Ingo Molnar:
 "The main changes in this cycle were:

   - A comprehensive rewrite of the robust/PI futex code's exit handling
     to fix various exit races. (Thomas Gleixner et al)

   - Rework the generic REFCOUNT_FULL implementation using
     atomic_fetch_* operations so that the performance impact of the
     cmpxchg() loops is mitigated for common refcount operations.

     With these performance improvements the generic implementation of
     refcount_t should be good enough for everybody - and this got
     confirmed by performance testing, so remove ARCH_HAS_REFCOUNT and
     REFCOUNT_FULL entirely, leaving the generic implementation enabled
     unconditionally. (Will Deacon)

   - Other misc changes, fixes, cleanups"

* 'locking-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (27 commits)
  lkdtm: Remove references to CONFIG_REFCOUNT_FULL
  locking/refcount: Remove unused 'refcount_error_report()' function
  locking/refcount: Consolidate implementations of refcount_t
  locking/refcount: Consolidate REFCOUNT_{MAX,SATURATED} definitions
  locking/refcount: Move saturation warnings out of line
  locking/refcount: Improve performance of generic REFCOUNT_FULL code
  locking/refcount: Move the bulk of the REFCOUNT_FULL implementation into the <linux/refcount.h> header
  locking/refcount: Remove unused refcount_*_checked() variants
  locking/refcount: Ensure integer operands are treated as signed
  locking/refcount: Define constants for saturation and max refcount values
  futex: Prevent exit livelock
  futex: Provide distinct return value when owner is exiting
  futex: Add mutex around futex exit
  futex: Provide state handling for exec() as well
  futex: Sanitize exit state handling
  futex: Mark the begin of futex exit explicitly
  futex: Set task::futex_state to DEAD right after handling futex exit
  futex: Split futex_mm_release() for exit/exec
  exit/exec: Seperate mm_release()
  futex: Replace PF_EXITPIDONE with a state
  ...
  • Loading branch information
torvalds committed Nov 27, 2019
2 parents 1ae7878 + 500543c commit 168829a
Show file tree
Hide file tree
Showing 56 changed files with 686 additions and 716 deletions.
21 changes: 0 additions & 21 deletions arch/Kconfig
Expand Up @@ -892,27 +892,6 @@ config STRICT_MODULE_RWX
config ARCH_HAS_PHYS_TO_DMA
bool

config ARCH_HAS_REFCOUNT
bool
help
An architecture selects this when it has implemented refcount_t
using open coded assembly primitives that provide an optimized
refcount_t implementation, possibly at the expense of some full
refcount state checks of CONFIG_REFCOUNT_FULL=y.

The refcount overflow check behavior, however, must be retained.
Catching overflows is the primary security concern for protecting
against bugs in reference counts.

config REFCOUNT_FULL
bool "Perform full reference count validation at the expense of speed"
help
Enabling this switches the refcounting infrastructure from a fast
unchecked atomic_t implementation to a fully state checked
implementation, which can be (slightly) slower but provides protections
against various use-after-free conditions that can be used in
security flaw exploits.

config HAVE_ARCH_COMPILER_H
bool
help
Expand Down
1 change: 0 additions & 1 deletion arch/arm/Kconfig
Expand Up @@ -117,7 +117,6 @@ config ARM
select OLD_SIGSUSPEND3
select PCI_SYSCALL if PCI
select PERF_USE_VMALLOC
select REFCOUNT_FULL
select RTC_LIB
select SYS_SUPPORTS_APM_EMULATION
# Above selects are sorted alphabetically; please add new ones
Expand Down
1 change: 0 additions & 1 deletion arch/arm64/Kconfig
Expand Up @@ -182,7 +182,6 @@ config ARM64
select PCI_SYSCALL if PCI
select POWER_RESET
select POWER_SUPPLY
select REFCOUNT_FULL
select SPARSE_IRQ
select SWIOTLB
select SYSCTL_EXCEPTION_TRACE
Expand Down
1 change: 0 additions & 1 deletion arch/s390/configs/debug_defconfig
Expand Up @@ -62,7 +62,6 @@ CONFIG_OPROFILE=m
CONFIG_KPROBES=y
CONFIG_JUMP_LABEL=y
CONFIG_STATIC_KEYS_SELFTEST=y
CONFIG_REFCOUNT_FULL=y
CONFIG_LOCK_EVENT_COUNTS=y
CONFIG_MODULES=y
CONFIG_MODULE_FORCE_LOAD=y
Expand Down
1 change: 0 additions & 1 deletion arch/x86/Kconfig
Expand Up @@ -73,7 +73,6 @@ config X86
select ARCH_HAS_PMEM_API if X86_64
select ARCH_HAS_PTE_DEVMAP if X86_64
select ARCH_HAS_PTE_SPECIAL
select ARCH_HAS_REFCOUNT
select ARCH_HAS_UACCESS_FLUSHCACHE if X86_64
select ARCH_HAS_UACCESS_MCSAFE if X86_64 && X86_MCE
select ARCH_HAS_SET_MEMORY
Expand Down
6 changes: 0 additions & 6 deletions arch/x86/include/asm/asm.h
Expand Up @@ -141,9 +141,6 @@
# define _ASM_EXTABLE_EX(from, to) \
_ASM_EXTABLE_HANDLE(from, to, ex_handler_ext)

# define _ASM_EXTABLE_REFCOUNT(from, to) \
_ASM_EXTABLE_HANDLE(from, to, ex_handler_refcount)

# define _ASM_NOKPROBE(entry) \
.pushsection "_kprobe_blacklist","aw" ; \
_ASM_ALIGN ; \
Expand Down Expand Up @@ -172,9 +169,6 @@
# define _ASM_EXTABLE_EX(from, to) \
_ASM_EXTABLE_HANDLE(from, to, ex_handler_ext)

# define _ASM_EXTABLE_REFCOUNT(from, to) \
_ASM_EXTABLE_HANDLE(from, to, ex_handler_refcount)

/* For C file, we already have NOKPROBE_SYMBOL macro */
#endif

Expand Down
126 changes: 0 additions & 126 deletions arch/x86/include/asm/refcount.h

This file was deleted.

49 changes: 0 additions & 49 deletions arch/x86/mm/extable.c
Expand Up @@ -44,55 +44,6 @@ __visible bool ex_handler_fault(const struct exception_table_entry *fixup,
}
EXPORT_SYMBOL_GPL(ex_handler_fault);

/*
* Handler for UD0 exception following a failed test against the
* result of a refcount inc/dec/add/sub.
*/
__visible bool ex_handler_refcount(const struct exception_table_entry *fixup,
struct pt_regs *regs, int trapnr,
unsigned long error_code,
unsigned long fault_addr)
{
/* First unconditionally saturate the refcount. */
*(int *)regs->cx = INT_MIN / 2;

/*
* Strictly speaking, this reports the fixup destination, not
* the fault location, and not the actually overflowing
* instruction, which is the instruction before the "js", but
* since that instruction could be a variety of lengths, just
* report the location after the overflow, which should be close
* enough for finding the overflow, as it's at least back in
* the function, having returned from .text.unlikely.
*/
regs->ip = ex_fixup_addr(fixup);

/*
* This function has been called because either a negative refcount
* value was seen by any of the refcount functions, or a zero
* refcount value was seen by refcount_dec().
*
* If we crossed from INT_MAX to INT_MIN, OF (Overflow Flag: result
* wrapped around) will be set. Additionally, seeing the refcount
* reach 0 will set ZF (Zero Flag: result was zero). In each of
* these cases we want a report, since it's a boundary condition.
* The SF case is not reported since it indicates post-boundary
* manipulations below zero or above INT_MAX. And if none of the
* flags are set, something has gone very wrong, so report it.
*/
if (regs->flags & (X86_EFLAGS_OF | X86_EFLAGS_ZF)) {
bool zero = regs->flags & X86_EFLAGS_ZF;

refcount_error_report(regs, zero ? "hit zero" : "overflow");
} else if ((regs->flags & X86_EFLAGS_SF) == 0) {
/* Report if none of OF, ZF, nor SF are set. */
refcount_error_report(regs, "unexpected saturation");
}

return true;
}
EXPORT_SYMBOL(ex_handler_refcount);

/*
* Handler for when we fail to restore a task's FPU state. We should never get
* here because the FPU state of a task using the FPU (task->thread.fpu.state)
Expand Down
2 changes: 1 addition & 1 deletion drivers/gpu/drm/drm_connector.c
Expand Up @@ -719,7 +719,7 @@ void drm_connector_list_iter_end(struct drm_connector_list_iter *iter)
__drm_connector_put_safe(iter->conn);
spin_unlock_irqrestore(&config->connector_list_lock, flags);
}
lock_release(&connector_list_iter_dep_map, 0, _RET_IP_);
lock_release(&connector_list_iter_dep_map, _RET_IP_);
}
EXPORT_SYMBOL(drm_connector_list_iter_end);

Expand Down
1 change: 0 additions & 1 deletion drivers/gpu/drm/i915/Kconfig.debug
Expand Up @@ -22,7 +22,6 @@ config DRM_I915_DEBUG
depends on DRM_I915
select DEBUG_FS
select PREEMPT_COUNT
select REFCOUNT_FULL
select I2C_CHARDEV
select STACKDEPOT
select DRM_DP_AUX_CHARDEV
Expand Down
6 changes: 3 additions & 3 deletions drivers/gpu/drm/i915/gem/i915_gem_shrinker.c
Expand Up @@ -509,14 +509,14 @@ void i915_gem_shrinker_taints_mutex(struct drm_i915_private *i915,
I915_MM_SHRINKER, 0, _RET_IP_);

mutex_acquire(&mutex->dep_map, 0, 0, _RET_IP_);
mutex_release(&mutex->dep_map, 0, _RET_IP_);
mutex_release(&mutex->dep_map, _RET_IP_);

mutex_release(&i915->drm.struct_mutex.dep_map, 0, _RET_IP_);
mutex_release(&i915->drm.struct_mutex.dep_map, _RET_IP_);

fs_reclaim_release(GFP_KERNEL);

if (unlock)
mutex_release(&i915->drm.struct_mutex.dep_map, 0, _RET_IP_);
mutex_release(&i915->drm.struct_mutex.dep_map, _RET_IP_);
}

#define obj_to_i915(obj__) to_i915((obj__)->base.dev)
Expand Down
2 changes: 1 addition & 1 deletion drivers/gpu/drm/i915/gt/intel_engine_pm.c
Expand Up @@ -52,7 +52,7 @@ static inline unsigned long __timeline_mark_lock(struct intel_context *ce)
static inline void __timeline_mark_unlock(struct intel_context *ce,
unsigned long flags)
{
mutex_release(&ce->timeline->mutex.dep_map, 0, _THIS_IP_);
mutex_release(&ce->timeline->mutex.dep_map, _THIS_IP_);
local_irq_restore(flags);
}

Expand Down
2 changes: 1 addition & 1 deletion drivers/gpu/drm/i915/i915_request.c
Expand Up @@ -1495,7 +1495,7 @@ long i915_request_wait(struct i915_request *rq,
dma_fence_remove_callback(&rq->fence, &wait.cb);

out:
mutex_release(&rq->engine->gt->reset.mutex.dep_map, 0, _THIS_IP_);
mutex_release(&rq->engine->gt->reset.mutex.dep_map, _THIS_IP_);
trace_i915_request_wait_end(rq);
return timeout;
}
Expand Down
11 changes: 1 addition & 10 deletions drivers/misc/lkdtm/refcount.c
Expand Up @@ -6,14 +6,6 @@
#include "lkdtm.h"
#include <linux/refcount.h>

#ifdef CONFIG_REFCOUNT_FULL
#define REFCOUNT_MAX (UINT_MAX - 1)
#define REFCOUNT_SATURATED UINT_MAX
#else
#define REFCOUNT_MAX INT_MAX
#define REFCOUNT_SATURATED (INT_MIN / 2)
#endif

static void overflow_check(refcount_t *ref)
{
switch (refcount_read(ref)) {
Expand Down Expand Up @@ -127,7 +119,7 @@ void lkdtm_REFCOUNT_DEC_ZERO(void)
static void check_negative(refcount_t *ref, int start)
{
/*
* CONFIG_REFCOUNT_FULL refuses to move a refcount at all on an
* refcount_t refuses to move a refcount at all on an
* over-sub, so we have to track our starting position instead of
* looking only at zero-pinning.
*/
Expand Down Expand Up @@ -210,7 +202,6 @@ static void check_from_zero(refcount_t *ref)

/*
* A refcount_inc() from zero should pin to zero or saturate and may WARN.
* Only CONFIG_REFCOUNT_FULL provides this protection currently.
*/
void lkdtm_REFCOUNT_INC_ZERO(void)
{
Expand Down
8 changes: 4 additions & 4 deletions drivers/tty/tty_ldsem.c
Expand Up @@ -303,7 +303,7 @@ static int __ldsem_down_read_nested(struct ld_semaphore *sem,
if (count <= 0) {
lock_contended(&sem->dep_map, _RET_IP_);
if (!down_read_failed(sem, count, timeout)) {
rwsem_release(&sem->dep_map, 1, _RET_IP_);
rwsem_release(&sem->dep_map, _RET_IP_);
return 0;
}
}
Expand All @@ -322,7 +322,7 @@ static int __ldsem_down_write_nested(struct ld_semaphore *sem,
if ((count & LDSEM_ACTIVE_MASK) != LDSEM_ACTIVE_BIAS) {
lock_contended(&sem->dep_map, _RET_IP_);
if (!down_write_failed(sem, count, timeout)) {
rwsem_release(&sem->dep_map, 1, _RET_IP_);
rwsem_release(&sem->dep_map, _RET_IP_);
return 0;
}
}
Expand Down Expand Up @@ -390,7 +390,7 @@ void ldsem_up_read(struct ld_semaphore *sem)
{
long count;

rwsem_release(&sem->dep_map, 1, _RET_IP_);
rwsem_release(&sem->dep_map, _RET_IP_);

count = atomic_long_add_return(-LDSEM_READ_BIAS, &sem->count);
if (count < 0 && (count & LDSEM_ACTIVE_MASK) == 0)
Expand All @@ -404,7 +404,7 @@ void ldsem_up_write(struct ld_semaphore *sem)
{
long count;

rwsem_release(&sem->dep_map, 1, _RET_IP_);
rwsem_release(&sem->dep_map, _RET_IP_);

count = atomic_long_add_return(-LDSEM_WRITE_BIAS, &sem->count);
if (count < 0)
Expand Down
2 changes: 1 addition & 1 deletion fs/dcache.c
Expand Up @@ -1319,7 +1319,7 @@ static void d_walk(struct dentry *parent, void *data,

if (!list_empty(&dentry->d_subdirs)) {
spin_unlock(&this_parent->d_lock);
spin_release(&dentry->d_lock.dep_map, 1, _RET_IP_);
spin_release(&dentry->d_lock.dep_map, _RET_IP_);
this_parent = dentry;
spin_acquire(&this_parent->d_lock.dep_map, 0, 1, _RET_IP_);
goto repeat;
Expand Down

0 comments on commit 168829a

Please sign in to comment.