1. 01 6月, 2018 1 次提交
  2. 12 4月, 2018 1 次提交
    • M
      mm: introduce MAP_FIXED_NOREPLACE · a4ff8e86
      Michal Hocko 提交于
      Patch series "mm: introduce MAP_FIXED_NOREPLACE", v2.
      
      This has started as a follow up discussion [3][4] resulting in the
      runtime failure caused by hardening patch [5] which removes MAP_FIXED
      from the elf loader because MAP_FIXED is inherently dangerous as it
      might silently clobber an existing underlying mapping (e.g.  stack).
      The reason for the failure is that some architectures enforce an
      alignment for the given address hint without MAP_FIXED used (e.g.  for
      shared or file backed mappings).
      
      One way around this would be excluding those archs which do alignment
      tricks from the hardening [6].  The patch is really trivial but it has
      been objected, rightfully so, that this screams for a more generic
      solution.  We basically want a non-destructive MAP_FIXED.
      
      The first patch introduced MAP_FIXED_NOREPLACE which enforces the given
      address but unlike MAP_FIXED it fails with EEXIST if the given range
      conflicts with an existing one.  The flag is introduced as a completely
      new one rather than a MAP_FIXED extension because of the backward
      compatibility.  We really want a never-clobber semantic even on older
      kernels which do not recognize the flag.  Unfortunately mmap sucks
      wrt flags evaluation because we do not EINVAL on unknown flags.  On
      those kernels we would simply use the traditional hint based semantic so
      the caller can still get a different address (which sucks) but at least
      not silently corrupt an existing mapping.  I do not see a good way
      around that.  Except we won't export expose the new semantic to the
      userspace at all.
      
      It seems there are users who would like to have something like that.
      Jemalloc has been mentioned by Michael Ellerman [7]
      
      Florian Weimer has mentioned the following:
      : glibc ld.so currently maps DSOs without hints.  This means that the kernel
      : will map right next to each other, and the offsets between them a completely
      : predictable.  We would like to change that and supply a random address in a
      : window of the address space.  If there is a conflict, we do not want the
      : kernel to pick a non-random address. Instead, we would try again with a
      : random address.
      
      John Hubbard has mentioned CUDA example
      : a) Searches /proc/<pid>/maps for a "suitable" region of available
      : VA space.  "Suitable" generally means it has to have a base address
      : within a certain limited range (a particular device model might
      : have odd limitations, for example), it has to be large enough, and
      : alignment has to be large enough (again, various devices may have
      : constraints that lead us to do this).
      :
      : This is of course subject to races with other threads in the process.
      :
      : Let's say it finds a region starting at va.
      :
      : b) Next it does:
      :     p = mmap(va, ...)
      :
      : *without* setting MAP_FIXED, of course (so va is just a hint), to
      : attempt to safely reserve that region. If p != va, then in most cases,
      : this is a failure (almost certainly due to another thread getting a
      : mapping from that region before we did), and so this layer now has to
      : call munmap(), before returning a "failure: retry" to upper layers.
      :
      :     IMPROVEMENT: --> if instead, we could call this:
      :
      :             p = mmap(va, ... MAP_FIXED_NOREPLACE ...)
      :
      :         , then we could skip the munmap() call upon failure. This
      :         is a small thing, but it is useful here. (Thanks to Piotr
      :         Jaroszynski and Mark Hairgrove for helping me get that detail
      :         exactly right, btw.)
      :
      : c) After that, CUDA suballocates from p, via:
      :
      :      q = mmap(sub_region_start, ... MAP_FIXED ...)
      :
      : Interestingly enough, "freeing" is also done via MAP_FIXED, and
      : setting PROT_NONE to the subregion. Anyway, I just included (c) for
      : general interest.
      
      Atomic address range probing in the multithreaded programs in general
      sounds like an interesting thing to me.
      
      The second patch simply replaces MAP_FIXED use in elf loader by
      MAP_FIXED_NOREPLACE.  I believe other places which rely on MAP_FIXED
      should follow.  Actually real MAP_FIXED usages should be docummented
      properly and they should be more of an exception.
      
      [1] http://lkml.kernel.org/r/20171116101900.13621-1-mhocko@kernel.org
      [2] http://lkml.kernel.org/r/20171129144219.22867-1-mhocko@kernel.org
      [3] http://lkml.kernel.org/r/20171107162217.382cd754@canb.auug.org.au
      [4] http://lkml.kernel.org/r/1510048229.12079.7.camel@abdul.in.ibm.com
      [5] http://lkml.kernel.org/r/20171023082608.6167-1-mhocko@kernel.org
      [6] http://lkml.kernel.org/r/20171113094203.aofz2e7kueitk55y@dhcp22.suse.cz
      [7] http://lkml.kernel.org/r/87efp1w7vy.fsf@concordia.ellerman.id.au
      
      This patch (of 2):
      
      MAP_FIXED is used quite often to enforce mapping at the particular range.
      The main problem of this flag is, however, that it is inherently dangerous
      because it unmaps existing mappings covered by the requested range.  This
      can cause silent memory corruptions.  Some of them even with serious
      security implications.  While the current semantic might be really
      desiderable in many cases there are others which would want to enforce the
      given range but rather see a failure than a silent memory corruption on a
      clashing range.  Please note that there is no guarantee that a given range
      is obeyed by the mmap even when it is free - e.g.  arch specific code is
      allowed to apply an alignment.
      
      Introduce a new MAP_FIXED_NOREPLACE flag for mmap to achieve this
      behavior.  It has the same semantic as MAP_FIXED wrt.  the given address
      request with a single exception that it fails with EEXIST if the requested
      address is already covered by an existing mapping.  We still do rely on
      get_unmaped_area to handle all the arch specific MAP_FIXED treatment and
      check for a conflicting vma after it returns.
      
      The flag is introduced as a completely new one rather than a MAP_FIXED
      extension because of the backward compatibility.  We really want a
      never-clobber semantic even on older kernels which do not recognize the
      flag.  Unfortunately mmap sucks wrt.  flags evaluation because we do not
      EINVAL on unknown flags.  On those kernels we would simply use the
      traditional hint based semantic so the caller can still get a different
      address (which sucks) but at least not silently corrupt an existing
      mapping.  I do not see a good way around that.
      
      [mpe@ellerman.id.au: fix whitespace]
      [fail on clashing range with EEXIST as per Florian Weimer]
      [set MAP_FIXED before round_hint_to_min as per Khalid Aziz]
      Link: http://lkml.kernel.org/r/20171213092550.2774-2-mhocko@kernel.orgReviewed-by: NKhalid Aziz <khalid.aziz@oracle.com>
      Signed-off-by: NMichal Hocko <mhocko@suse.com>
      Acked-by: NMichael Ellerman <mpe@ellerman.id.au>
      Cc: Khalid Aziz <khalid.aziz@oracle.com>
      Cc: Russell King - ARM Linux <linux@armlinux.org.uk>
      Cc: Andrea Arcangeli <aarcange@redhat.com>
      Cc: Florian Weimer <fweimer@redhat.com>
      Cc: John Hubbard <jhubbard@nvidia.com>
      Cc: Matthew Wilcox <willy@infradead.org>
      Cc: Abdul Haleem <abdhalee@linux.vnet.ibm.com>
      Cc: Joel Stanley <joel@jms.id.au>
      Cc: Kees Cook <keescook@chromium.org>
      Cc: Michal Hocko <mhocko@suse.com>
      Cc: Jason Evans <jasone@google.com>
      Cc: David Goldblatt <davidtgoldblatt@gmail.com>
      Cc: Edward Tomasz Napierała <trasz@FreeBSD.org>
      Cc: Anshuman Khandual <khandual@linux.vnet.ibm.com>
      Signed-off-by: NAndrew Morton <akpm@linux-foundation.org>
      Signed-off-by: NLinus Torvalds <torvalds@linux-foundation.org>
      a4ff8e86
  3. 08 4月, 2018 4 次提交
  4. 03 4月, 2018 1 次提交
  5. 28 3月, 2018 2 次提交
    • A
      alpha: get rid of pointless insn in ret_from_kernel_thread · 206b1c60
      Al Viro 提交于
      	It used to clear a3, so that signal handling on
      return to userland would've passed zero r0 to do_work_pending(),
      preventing the syscall restart logics from triggering.
      
      	It had been pointless all along, since we only go there
      after successful do_execve().  Which does clear regs->r0 on alpha,
      preventing the syscall restart logics just fine, no extra help
      needed.  Good thing, that, since back in 2012 do_work_pending()
      has lost the second argument, shifting the registers used to pass
      that thing from a3 to a2.  Commit that had done that adjusted the
      entry.S code accordingly, but missed that one.
      
      	As the result, we were left with useless insn in
      ret_from_kernel_thread and confusing comment to go with it.
      Get rid of both...
      Signed-off-by: NAl Viro <viro@zeniv.linux.org.uk>
      206b1c60
    • A
      alpha: switch pci syscalls to SYSCALL_DEFINE · e4eacd6b
      Al Viro 提交于
      Signed-off-by: NAl Viro <viro@zeniv.linux.org.uk>
      e4eacd6b
  6. 17 3月, 2018 1 次提交
  7. 16 3月, 2018 1 次提交
  8. 12 3月, 2018 2 次提交
    • P
      perf/core: Remove perf_event::group_entry · 8343aae6
      Peter Zijlstra 提交于
      Now that all the grouping is done with RB trees, we no longer need
      group_entry and can replace the whole thing with sibling_list.
      Signed-off-by: NPeter Zijlstra (Intel) <peterz@infradead.org>
      Acked-by: NMark Rutland <mark.rutland@arm.com>
      Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
      Cc: Alexey Budankov <alexey.budankov@linux.intel.com>
      Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
      Cc: David Carrillo-Cisneros <davidcc@google.com>
      Cc: Dmitri Prokhorov <Dmitry.Prohorov@intel.com>
      Cc: Jiri Olsa <jolsa@redhat.com>
      Cc: Kan Liang <kan.liang@intel.com>
      Cc: Linus Torvalds <torvalds@linux-foundation.org>
      Cc: Stephane Eranian <eranian@google.com>
      Cc: Thomas Gleixner <tglx@linutronix.de>
      Cc: Valery Cherepennikov <valery.cherepennikov@intel.com>
      Cc: Vince Weaver <vincent.weaver@maine.edu>
      Cc: linux-kernel@vger.kernel.org
      Signed-off-by: NIngo Molnar <mingo@kernel.org>
      8343aae6
    • A
      locking/xchg/alpha: Remove superfluous memory barriers from the _local() variants · fbfcd019
      Andrea Parri 提交于
      The following two commits:
      
        79d44246 ("locking/xchg/alpha: Clean up barrier usage by using smp_mb() in place of __ASM__MB")
        472e8c55 ("locking/xchg/alpha: Fix xchg() and cmpxchg() memory ordering bugs")
      
      ... ended up adding unnecessary barriers to the _local() variants on Alpha,
      which the previous code took care to avoid.
      
      Fix them by adding the smp_mb() into the cmpxchg() macro rather than into the
      ____cmpxchg() variants.
      Reported-by: NWill Deacon <will.deacon@arm.com>
      Signed-off-by: NAndrea Parri <parri.andrea@gmail.com>
      Cc: Alan Stern <stern@rowland.harvard.edu>
      Cc: Andrew Morton <akpm@linux-foundation.org>
      Cc: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
      Cc: Linus Torvalds <torvalds@linux-foundation.org>
      Cc: Matt Turner <mattst88@gmail.com>
      Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
      Cc: Peter Zijlstra <peterz@infradead.org>
      Cc: Richard Henderson <rth@twiddle.net>
      Cc: Thomas Gleixner <tglx@linutronix.de>
      Cc: linux-alpha@vger.kernel.org
      Fixes: 472e8c55 ("locking/xchg/alpha: Fix xchg() and cmpxchg() memory ordering bugs")
      Fixes: 79d44246 ("locking/xchg/alpha: Clean up barrier usage by using smp_mb() in place of __ASM__MB")
      Link: http://lkml.kernel.org/r/1519704058-13430-1-git-send-email-parri.andrea@gmail.comSigned-off-by: NIngo Molnar <mingo@kernel.org>
      fbfcd019
  9. 23 2月, 2018 2 次提交
  10. 21 2月, 2018 1 次提交
  11. 26 1月, 2018 2 次提交
    • A
      alpha: osf_sys.c: use timespec64 where appropriate · ce4c2535
      Arnd Bergmann 提交于
      Some of the syscall helper functions (do_utimes, poll_select_set_timeout,
      core_sys_select) have changed over the past year or two to use
      'timespec64' pointers rather than 'timespec'. This was fine on alpha,
      since 64-bit architectures treat the two as the same type.
      
      However, I'd like to change that behavior and make 'timespec64' a proper
      type of its own even on 64-bit architectures, and that will introduce
      harmless type mismatch warnings here.
      
      Also, I'm trying to kill off the do_gettimeofday() helper in favor of
      ktime_get() and related interfaces throughout the kernel.
      
      This changes the get_tv32/put_tv32 helper functions to also take a
      timespec64 argument rather than timeval, which allows us to simplify
      some of the syscall helpers a bit and avoid the type warnings.
      
      For the moment, wait4 and adjtimex are still better off with the old
      behavior, so I'm adding a special put_tv_to_tv32() helper for those.
      Signed-off-by: NArnd Bergmann <arnd@arndb.de>
      Signed-off-by: NAl Viro <viro@zeniv.linux.org.uk>
      ce4c2535
    • A
      alpha: osf_sys.c: fix put_tv32 regression · 47669fb6
      Arnd Bergmann 提交于
      There was a typo in the new version of put_tv32() that caused an unguarded
      access of a user space pointer, and failed to return the correct result in
      gettimeofday(), wait4(), usleep_thread() and old_adjtimex().
      
      This fixes it to give the correct behavior again.
      
      Cc: stable@vger.kernel.org
      Fixes: 1cc6c463 ("osf_sys.c: switch handling of timeval32/itimerval32 to copy_{to,from}_user()")
      Signed-off-by: NArnd Bergmann <arnd@arndb.de>
      Signed-off-by: NAl Viro <viro@zeniv.linux.org.uk>
      47669fb6
  12. 21 1月, 2018 10 次提交
    • M
      alpha: fix crash if pthread_create races with signal delivery · 21ffceda
      Mikulas Patocka 提交于
      On alpha, a process will crash if it attempts to start a thread and a
      signal is delivered at the same time. The crash can be reproduced with
      this program: https://cygwin.com/ml/cygwin/2014-11/msg00473.html
      
      The reason for the crash is this:
      * we call the clone syscall
      * we go to the function copy_process
      * copy process calls copy_thread_tls, it is a wrapper around copy_thread
      * copy_thread sets the tls pointer: childti->pcb.unique = regs->r20
      * copy_thread sets regs->r20 to zero
      * we go back to copy_process
      * copy process checks "if (signal_pending(current))" and returns
        -ERESTARTNOINTR
      * the clone syscall is restarted, but this time, regs->r20 is zero, so
        the new thread is created with zero tls pointer
      * the new thread crashes in start_thread when attempting to access tls
      
      The comment in the code says that setting the register r20 is some
      compatibility with OSF/1. But OSF/1 doesn't use the CLONE_SETTLS flag, so
      we don't have to zero r20 if CLONE_SETTLS is set. This patch fixes the bug
      by zeroing regs->r20 only if CLONE_SETTLS is not set.
      Signed-off-by: NMikulas Patocka <mpatocka@redhat.com>
      Cc: stable@vger.kernel.org
      Signed-off-by: NMatt Turner <mattst88@gmail.com>
      21ffceda
    • M
      alpha: fix formating of stack content · 4b01abdb
      Mikulas Patocka 提交于
      Since version 4.9, the kernel automatically breaks printk calls into
      multiple newlines unless pr_cont is used. Fix the alpha stacktrace code,
      so that it prints stack trace in four columns, as it was initially
      intended.
      Signed-off-by: NMikulas Patocka <mpatocka@redhat.com>
      Cc: stable@vger.kernel.org	# v4.9+
      Signed-off-by: NMatt Turner <mattst88@gmail.com>
      4b01abdb
    • M
      alpha: fix reboot on Avanti platform · 55fc633c
      Mikulas Patocka 提交于
      We need to define NEED_SRM_SAVE_RESTORE on the Avanti, otherwise we get
      machine check exception when attempting to reboot the machine.
      Signed-off-by: NMikulas Patocka <mpatocka@redhat.com>
      Cc: stable@vger.kernel.org
      Signed-off-by: NMatt Turner <mattst88@gmail.com>
      55fc633c
    • S
      alpha: deprecate pci_get_bus_and_slot() · 797cfc4f
      Sinan Kaya 提交于
      pci_get_bus_and_slot() is restrictive such that it assumes domain=0 as
      where a PCI device is present. This restricts the device drivers to be
      reused for other domain numbers.
      
      Use pci_get_domain_bus_and_slot() with a domain number of 0 where we can't
      extract the domain number. Other places, use the actual domain number from
      the device.
      Signed-off-by: NSinan Kaya <okaya@codeaurora.org>
      Signed-off-by: NMatt Turner <mattst88@gmail.com>
      797cfc4f
    • M
      alpha: Fix mixed up args in EXC macro in futex operations · 84e45536
      Michael Cree 提交于
      Fix the typo (mixed up arguments) in the EXC macro in the futex
      definitions introduced by commit ca282f69 (alpha: add a
      helper for emitting exception table entries).
      
      Cc: stable@vger.kernel.org      # v4.12+
      Signed-off-by: NMichael Cree <mcree@orcon.net.nz>
      Signed-off-by: NMatt Turner <mattst88@gmail.com>
      84e45536
    • A
      alpha: osf_sys.c: use timespec64 where appropriate · d437e065
      Arnd Bergmann 提交于
      Some of the syscall helper functions (do_utimes, poll_select_set_timeout,
      core_sys_select) have changed over the past year or two to use
      'timespec64' pointers rather than 'timespec'. This was fine on alpha,
      since 64-bit architectures treat the two as the same type.
      
      However, I'd like to change that behavior and make 'timespec64' a proper
      type of its own even on 64-bit architectures, and that will introduce
      harmless type mismatch warnings here.
      
      Also, I'm trying to kill off the do_gettimeofday() helper in favor of
      ktime_get() and related interfaces throughout the kernel.
      
      This changes the get_tv32/put_tv32 helper functions to also take a
      timespec64 argument rather than timeval, which allows us to simplify
      some of the syscall helpers a bit and avoid the type warnings.
      
      For the moment, wait4 and adjtimex are still better off with the old
      behavior, so I'm adding a special put_tv_to_tv32() helper for those.
      Signed-off-by: NArnd Bergmann <arnd@arndb.de>
      Signed-off-by: NMatt Turner <mattst88@gmail.com>
      d437e065
    • A
      alpha: osf_sys.c: fix put_tv32 regression · 645a05a7
      Arnd Bergmann 提交于
      There was a typo in the new version of put_tv32() that caused an unguarded
      access of a user space pointer, and failed to return the correct result in
      gettimeofday(), wait4(), usleep_thread() and old_adjtimex().
      
      This fixes it to give the correct behavior again.
      
      Cc: stable@vger.kernel.org
      Fixes: 1cc6c463 ("osf_sys.c: switch handling of timeval32/itimerval32 to copy_{to,from}_user()")
      Signed-off-by: NArnd Bergmann <arnd@arndb.de>
      Signed-off-by: NMatt Turner <mattst88@gmail.com>
      645a05a7
    • T
      alpha: make thread_saved_pc static · 16dc17ee
      Tobias Klauser 提交于
      The only user of thread_saved_pc() in non-arch-specific code was removed
      in commit 8243d559 ("sched/core: Remove pointless printout in
      sched_show_task()"), so it no longer needs to be globally defined for
      Alpha and can be made static.
      Signed-off-by: NTobias Klauser <tklauser@distanz.ch>
      Signed-off-by: NMatt Turner <mattst88@gmail.com>
      16dc17ee
    • E
      alpha: make XTABS equivalent to TAB3 · 77e5bff1
      Eugene Syromiatnikov 提交于
      XTABS is an old name for "expand tabs to spaces" flag, which was a
      separate flag on some BSD implementations. POSIX, however, specifies
      that this effect is enabled with TAB3 output mode.
      
      Currently, alpha is the only architecture that has the value of
      the XTABS flag not equivalent to TAB3.
      Signed-off-by: NEugene Syromiatnikov <esyr@redhat.com>
      Signed-off-by: NMatt Turner <mattst88@gmail.com>
      77e5bff1
    • L
      alpha/PCI: Fix noname IRQ level detection · 86be8993
      Lorenzo Pieralisi 提交于
      The conversion of the alpha architecture PCI host bridge legacy IRQ
      mapping/swizzling to the new PCI host bridge map/swizzle hooks carried
      out through:
      
      commit 0e4c2eeb ("alpha/PCI: Replace pci_fixup_irqs() call with
      host bridge IRQ mapping hooks")
      
      implies that IRQ for devices are now allocated through pci_assign_irq()
      function in pci_device_probe() that is called when a driver matching a
      device is found in order to probe the device through the device driver.
      
      Alpha noname platforms required IRQ level programming to be executed
      in sio_fixup_irq_levels(), that is called in noname_init_pci(), a
      platform hook called within a subsys_initcall.
      
      In noname_init_pci(), present IRQs are detected through
      sio_collect_irq_levels() that check the struct pci_dev->irq number
      to detect if an IRQ has been allocated for the device.
      
      By the time sio_collect_irq_levels() is called, some devices may still
      have not a matching driver loaded to match them (eg loadable module)
      therefore their IRQ allocation is still pending - which means that
      sio_collect_irq_levels() does not programme the correct IRQ level for
      those devices, causing their IRQ handling to be broken when the device
      driver is actually loaded and the device is probed.
      
      Fix the issue by adding code in the noname map_irq() function
      (noname_map_irq()) that, whilst mapping/swizzling the IRQ line, it also
      ensures that the correct IRQ level programming is executed at platform
      level, fixing the issue.
      
      Fixes: 0e4c2eeb ("alpha/PCI: Replace pci_fixup_irqs() call with
      host bridge IRQ mapping hooks")
      Reported-by: NMikulas Patocka <mpatocka@redhat.com>
      Signed-off-by: NLorenzo Pieralisi <lorenzo.pieralisi@arm.com>
      Cc: stable@vger.kernel.org # 4.14
      Cc: Bjorn Helgaas <bhelgaas@google.com>
      Cc: Richard Henderson <rth@twiddle.net>
      Cc: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
      Cc: Mikulas Patocka <mpatocka@redhat.com>
      Cc: Meelis Roos <mroos@linux.ee>
      Signed-off-by: NMatt Turner <mattst88@gmail.com>
      86be8993
  13. 17 1月, 2018 1 次提交
  14. 12 1月, 2018 1 次提交
  15. 10 1月, 2018 1 次提交
  16. 09 1月, 2018 1 次提交
  17. 04 1月, 2018 1 次提交
  18. 19 12月, 2017 1 次提交
    • B
      vgacon: Set VGA struct resource types · c8208411
      Bjorn Helgaas 提交于
      Set the resource type when we reserve VGA-related I/O port resources.
      
      The resource code doesn't actually look at the type, so it inserts
      resources without a type in the tree correctly even without this change.
      But if we ever print a resource without a type, it looks like this:
      
        vga+ [??? 0x000003c0-0x000003df flags 0x0]
      
      Setting the type means it will be printed correctly as:
      
        vga+ [io  0x000003c0-0x000003df]
      Signed-off-by: NBjorn Helgaas <bhelgaas@google.com>
      c8208411
  19. 05 12月, 2017 2 次提交
  20. 28 11月, 2017 1 次提交
  21. 22 11月, 2017 1 次提交
    • K
      treewide: setup_timer() -> timer_setup() · e99e88a9
      Kees Cook 提交于
      This converts all remaining cases of the old setup_timer() API into using
      timer_setup(), where the callback argument is the structure already
      holding the struct timer_list. These should have no behavioral changes,
      since they just change which pointer is passed into the callback with
      the same available pointers after conversion. It handles the following
      examples, in addition to some other variations.
      
      Casting from unsigned long:
      
          void my_callback(unsigned long data)
          {
              struct something *ptr = (struct something *)data;
          ...
          }
          ...
          setup_timer(&ptr->my_timer, my_callback, ptr);
      
      and forced object casts:
      
          void my_callback(struct something *ptr)
          {
          ...
          }
          ...
          setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr);
      
      become:
      
          void my_callback(struct timer_list *t)
          {
              struct something *ptr = from_timer(ptr, t, my_timer);
          ...
          }
          ...
          timer_setup(&ptr->my_timer, my_callback, 0);
      
      Direct function assignments:
      
          void my_callback(unsigned long data)
          {
              struct something *ptr = (struct something *)data;
          ...
          }
          ...
          ptr->my_timer.function = my_callback;
      
      have a temporary cast added, along with converting the args:
      
          void my_callback(struct timer_list *t)
          {
              struct something *ptr = from_timer(ptr, t, my_timer);
          ...
          }
          ...
          ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback;
      
      And finally, callbacks without a data assignment:
      
          void my_callback(unsigned long data)
          {
          ...
          }
          ...
          setup_timer(&ptr->my_timer, my_callback, 0);
      
      have their argument renamed to verify they're unused during conversion:
      
          void my_callback(struct timer_list *unused)
          {
          ...
          }
          ...
          timer_setup(&ptr->my_timer, my_callback, 0);
      
      The conversion is done with the following Coccinelle script:
      
      spatch --very-quiet --all-includes --include-headers \
      	-I ./arch/x86/include -I ./arch/x86/include/generated \
      	-I ./include -I ./arch/x86/include/uapi \
      	-I ./arch/x86/include/generated/uapi -I ./include/uapi \
      	-I ./include/generated/uapi --include ./include/linux/kconfig.h \
      	--dir . \
      	--cocci-file ~/src/data/timer_setup.cocci
      
      @fix_address_of@
      expression e;
      @@
      
       setup_timer(
      -&(e)
      +&e
       , ...)
      
      // Update any raw setup_timer() usages that have a NULL callback, but
      // would otherwise match change_timer_function_usage, since the latter
      // will update all function assignments done in the face of a NULL
      // function initialization in setup_timer().
      @change_timer_function_usage_NULL@
      expression _E;
      identifier _timer;
      type _cast_data;
      @@
      
      (
      -setup_timer(&_E->_timer, NULL, _E);
      +timer_setup(&_E->_timer, NULL, 0);
      |
      -setup_timer(&_E->_timer, NULL, (_cast_data)_E);
      +timer_setup(&_E->_timer, NULL, 0);
      |
      -setup_timer(&_E._timer, NULL, &_E);
      +timer_setup(&_E._timer, NULL, 0);
      |
      -setup_timer(&_E._timer, NULL, (_cast_data)&_E);
      +timer_setup(&_E._timer, NULL, 0);
      )
      
      @change_timer_function_usage@
      expression _E;
      identifier _timer;
      struct timer_list _stl;
      identifier _callback;
      type _cast_func, _cast_data;
      @@
      
      (
      -setup_timer(&_E->_timer, _callback, _E);
      +timer_setup(&_E->_timer, _callback, 0);
      |
      -setup_timer(&_E->_timer, &_callback, _E);
      +timer_setup(&_E->_timer, _callback, 0);
      |
      -setup_timer(&_E->_timer, _callback, (_cast_data)_E);
      +timer_setup(&_E->_timer, _callback, 0);
      |
      -setup_timer(&_E->_timer, &_callback, (_cast_data)_E);
      +timer_setup(&_E->_timer, _callback, 0);
      |
      -setup_timer(&_E->_timer, (_cast_func)_callback, _E);
      +timer_setup(&_E->_timer, _callback, 0);
      |
      -setup_timer(&_E->_timer, (_cast_func)&_callback, _E);
      +timer_setup(&_E->_timer, _callback, 0);
      |
      -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E);
      +timer_setup(&_E->_timer, _callback, 0);
      |
      -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E);
      +timer_setup(&_E->_timer, _callback, 0);
      |
      -setup_timer(&_E._timer, _callback, (_cast_data)_E);
      +timer_setup(&_E._timer, _callback, 0);
      |
      -setup_timer(&_E._timer, _callback, (_cast_data)&_E);
      +timer_setup(&_E._timer, _callback, 0);
      |
      -setup_timer(&_E._timer, &_callback, (_cast_data)_E);
      +timer_setup(&_E._timer, _callback, 0);
      |
      -setup_timer(&_E._timer, &_callback, (_cast_data)&_E);
      +timer_setup(&_E._timer, _callback, 0);
      |
      -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E);
      +timer_setup(&_E._timer, _callback, 0);
      |
      -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E);
      +timer_setup(&_E._timer, _callback, 0);
      |
      -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E);
      +timer_setup(&_E._timer, _callback, 0);
      |
      -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E);
      +timer_setup(&_E._timer, _callback, 0);
      |
       _E->_timer@_stl.function = _callback;
      |
       _E->_timer@_stl.function = &_callback;
      |
       _E->_timer@_stl.function = (_cast_func)_callback;
      |
       _E->_timer@_stl.function = (_cast_func)&_callback;
      |
       _E._timer@_stl.function = _callback;
      |
       _E._timer@_stl.function = &_callback;
      |
       _E._timer@_stl.function = (_cast_func)_callback;
      |
       _E._timer@_stl.function = (_cast_func)&_callback;
      )
      
      // callback(unsigned long arg)
      @change_callback_handle_cast
       depends on change_timer_function_usage@
      identifier change_timer_function_usage._callback;
      identifier change_timer_function_usage._timer;
      type _origtype;
      identifier _origarg;
      type _handletype;
      identifier _handle;
      @@
      
       void _callback(
      -_origtype _origarg
      +struct timer_list *t
       )
       {
      (
      	... when != _origarg
      	_handletype *_handle =
      -(_handletype *)_origarg;
      +from_timer(_handle, t, _timer);
      	... when != _origarg
      |
      	... when != _origarg
      	_handletype *_handle =
      -(void *)_origarg;
      +from_timer(_handle, t, _timer);
      	... when != _origarg
      |
      	... when != _origarg
      	_handletype *_handle;
      	... when != _handle
      	_handle =
      -(_handletype *)_origarg;
      +from_timer(_handle, t, _timer);
      	... when != _origarg
      |
      	... when != _origarg
      	_handletype *_handle;
      	... when != _handle
      	_handle =
      -(void *)_origarg;
      +from_timer(_handle, t, _timer);
      	... when != _origarg
      )
       }
      
      // callback(unsigned long arg) without existing variable
      @change_callback_handle_cast_no_arg
       depends on change_timer_function_usage &&
                           !change_callback_handle_cast@
      identifier change_timer_function_usage._callback;
      identifier change_timer_function_usage._timer;
      type _origtype;
      identifier _origarg;
      type _handletype;
      @@
      
       void _callback(
      -_origtype _origarg
      +struct timer_list *t
       )
       {
      +	_handletype *_origarg = from_timer(_origarg, t, _timer);
      +
      	... when != _origarg
      -	(_handletype *)_origarg
      +	_origarg
      	... when != _origarg
       }
      
      // Avoid already converted callbacks.
      @match_callback_converted
       depends on change_timer_function_usage &&
                  !change_callback_handle_cast &&
      	    !change_callback_handle_cast_no_arg@
      identifier change_timer_function_usage._callback;
      identifier t;
      @@
      
       void _callback(struct timer_list *t)
       { ... }
      
      // callback(struct something *handle)
      @change_callback_handle_arg
       depends on change_timer_function_usage &&
      	    !match_callback_converted &&
                  !change_callback_handle_cast &&
                  !change_callback_handle_cast_no_arg@
      identifier change_timer_function_usage._callback;
      identifier change_timer_function_usage._timer;
      type _handletype;
      identifier _handle;
      @@
      
       void _callback(
      -_handletype *_handle
      +struct timer_list *t
       )
       {
      +	_handletype *_handle = from_timer(_handle, t, _timer);
      	...
       }
      
      // If change_callback_handle_arg ran on an empty function, remove
      // the added handler.
      @unchange_callback_handle_arg
       depends on change_timer_function_usage &&
      	    change_callback_handle_arg@
      identifier change_timer_function_usage._callback;
      identifier change_timer_function_usage._timer;
      type _handletype;
      identifier _handle;
      identifier t;
      @@
      
       void _callback(struct timer_list *t)
       {
      -	_handletype *_handle = from_timer(_handle, t, _timer);
       }
      
      // We only want to refactor the setup_timer() data argument if we've found
      // the matching callback. This undoes changes in change_timer_function_usage.
      @unchange_timer_function_usage
       depends on change_timer_function_usage &&
                  !change_callback_handle_cast &&
                  !change_callback_handle_cast_no_arg &&
      	    !change_callback_handle_arg@
      expression change_timer_function_usage._E;
      identifier change_timer_function_usage._timer;
      identifier change_timer_function_usage._callback;
      type change_timer_function_usage._cast_data;
      @@
      
      (
      -timer_setup(&_E->_timer, _callback, 0);
      +setup_timer(&_E->_timer, _callback, (_cast_data)_E);
      |
      -timer_setup(&_E._timer, _callback, 0);
      +setup_timer(&_E._timer, _callback, (_cast_data)&_E);
      )
      
      // If we fixed a callback from a .function assignment, fix the
      // assignment cast now.
      @change_timer_function_assignment
       depends on change_timer_function_usage &&
                  (change_callback_handle_cast ||
                   change_callback_handle_cast_no_arg ||
                   change_callback_handle_arg)@
      expression change_timer_function_usage._E;
      identifier change_timer_function_usage._timer;
      identifier change_timer_function_usage._callback;
      type _cast_func;
      typedef TIMER_FUNC_TYPE;
      @@
      
      (
       _E->_timer.function =
      -_callback
      +(TIMER_FUNC_TYPE)_callback
       ;
      |
       _E->_timer.function =
      -&_callback
      +(TIMER_FUNC_TYPE)_callback
       ;
      |
       _E->_timer.function =
      -(_cast_func)_callback;
      +(TIMER_FUNC_TYPE)_callback
       ;
      |
       _E->_timer.function =
      -(_cast_func)&_callback
      +(TIMER_FUNC_TYPE)_callback
       ;
      |
       _E._timer.function =
      -_callback
      +(TIMER_FUNC_TYPE)_callback
       ;
      |
       _E._timer.function =
      -&_callback;
      +(TIMER_FUNC_TYPE)_callback
       ;
      |
       _E._timer.function =
      -(_cast_func)_callback
      +(TIMER_FUNC_TYPE)_callback
       ;
      |
       _E._timer.function =
      -(_cast_func)&_callback
      +(TIMER_FUNC_TYPE)_callback
       ;
      )
      
      // Sometimes timer functions are called directly. Replace matched args.
      @change_timer_function_calls
       depends on change_timer_function_usage &&
                  (change_callback_handle_cast ||
                   change_callback_handle_cast_no_arg ||
                   change_callback_handle_arg)@
      expression _E;
      identifier change_timer_function_usage._timer;
      identifier change_timer_function_usage._callback;
      type _cast_data;
      @@
      
       _callback(
      (
      -(_cast_data)_E
      +&_E->_timer
      |
      -(_cast_data)&_E
      +&_E._timer
      |
      -_E
      +&_E->_timer
      )
       )
      
      // If a timer has been configured without a data argument, it can be
      // converted without regard to the callback argument, since it is unused.
      @match_timer_function_unused_data@
      expression _E;
      identifier _timer;
      identifier _callback;
      @@
      
      (
      -setup_timer(&_E->_timer, _callback, 0);
      +timer_setup(&_E->_timer, _callback, 0);
      |
      -setup_timer(&_E->_timer, _callback, 0L);
      +timer_setup(&_E->_timer, _callback, 0);
      |
      -setup_timer(&_E->_timer, _callback, 0UL);
      +timer_setup(&_E->_timer, _callback, 0);
      |
      -setup_timer(&_E._timer, _callback, 0);
      +timer_setup(&_E._timer, _callback, 0);
      |
      -setup_timer(&_E._timer, _callback, 0L);
      +timer_setup(&_E._timer, _callback, 0);
      |
      -setup_timer(&_E._timer, _callback, 0UL);
      +timer_setup(&_E._timer, _callback, 0);
      |
      -setup_timer(&_timer, _callback, 0);
      +timer_setup(&_timer, _callback, 0);
      |
      -setup_timer(&_timer, _callback, 0L);
      +timer_setup(&_timer, _callback, 0);
      |
      -setup_timer(&_timer, _callback, 0UL);
      +timer_setup(&_timer, _callback, 0);
      |
      -setup_timer(_timer, _callback, 0);
      +timer_setup(_timer, _callback, 0);
      |
      -setup_timer(_timer, _callback, 0L);
      +timer_setup(_timer, _callback, 0);
      |
      -setup_timer(_timer, _callback, 0UL);
      +timer_setup(_timer, _callback, 0);
      )
      
      @change_callback_unused_data
       depends on match_timer_function_unused_data@
      identifier match_timer_function_unused_data._callback;
      type _origtype;
      identifier _origarg;
      @@
      
       void _callback(
      -_origtype _origarg
      +struct timer_list *unused
       )
       {
      	... when != _origarg
       }
      Signed-off-by: NKees Cook <keescook@chromium.org>
      e99e88a9
  22. 08 11月, 2017 2 次提交