]> Git Repo - J-linux.git/commitdiff
Merge tag 'random-5.19-rc1-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
authorLinus Torvalds <[email protected]>
Tue, 24 May 2022 18:58:10 +0000 (11:58 -0700)
committerLinus Torvalds <[email protected]>
Tue, 24 May 2022 18:58:10 +0000 (11:58 -0700)
Pull random number generator updates from Jason Donenfeld:
 "These updates continue to refine the work began in 5.17 and 5.18 of
  modernizing the RNG's crypto and streamlining and documenting its
  code.

  New for 5.19, the updates aim to improve entropy collection methods
  and make some initial decisions regarding the "premature next" problem
  and our threat model. The cloc utility now reports that random.c is
  931 lines of code and 466 lines of comments, not that basic metrics
  like that mean all that much, but at the very least it tells you that
  this is very much a manageable driver now.

  Here's a summary of the various updates:

   - The random_get_entropy() function now always returns something at
     least minimally useful. This is the primary entropy source in most
     collectors, which in the best case expands to something like RDTSC,
     but prior to this change, in the worst case it would just return 0,
     contributing nothing. For 5.19, additional architectures are wired
     up, and architectures that are entirely missing a cycle counter now
     have a generic fallback path, which uses the highest resolution
     clock available from the timekeeping subsystem.

     Some of those clocks can actually be quite good, despite the CPU
     not having a cycle counter of its own, and going off-core for a
     stamp is generally thought to increase jitter, something positive
     from the perspective of entropy gathering. Done very early on in
     the development cycle, this has been sitting in next getting some
     testing for a while now and has relevant acks from the archs, so it
     should be pretty well tested and fine, but is nonetheless the thing
     I'll be keeping my eye on most closely.

   - Of particular note with the random_get_entropy() improvements is
     MIPS, which, on CPUs that lack the c0 count register, will now
     combine the high-speed but short-cycle c0 random register with the
     lower-speed but long-cycle generic fallback path.

   - With random_get_entropy() now always returning something useful,
     the interrupt handler now collects entropy in a consistent
     construction.

   - Rather than comparing two samples of random_get_entropy() for the
     jitter dance, the algorithm now tests many samples, and uses the
     amount of differing ones to determine whether or not jitter entropy
     is usable and how laborious it must be. The problem with comparing
     only two samples was that if the cycle counter was extremely slow,
     but just so happened to be on the cusp of a change, the slowness
     wouldn't be detected. Taking many samples fixes that to some
     degree.

     This, combined with the other improvements to random_get_entropy(),
     should make future unification of /dev/random and /dev/urandom
     maybe more possible. At the very least, were we to attempt it again
     today (we're not), it wouldn't break any of Guenter's test rigs
     that broke when we tried it with 5.18. So, not today, but perhaps
     down the road, that's something we can revisit.

   - We attempt to reseed the RNG immediately upon waking up from system
     suspend or hibernation, making use of the various timestamps about
     suspend time and such available, as well as the usual inputs such
     as RDRAND when available.

   - Batched randomness now falls back to ordinary randomness before the
     RNG is initialized. This provides more consistent guarantees to the
     types of random numbers being returned by the various accessors.

   - The "pre-init injection" code is now gone for good. I suspect you
     in particular will be happy to read that, as I recall you
     expressing your distaste for it a few months ago. Instead, to avoid
     a "premature first" issue, while still allowing for maximal amount
     of entropy availability during system boot, the first 128 bits of
     estimated entropy are used immediately as it arrives, with the next
     128 bits being buffered. And, as before, after the RNG has been
     fully initialized, it winds up reseeding anyway a few seconds later
     in most cases. This resulted in a pretty big simplification of the
     initialization code and let us remove various ad-hoc mechanisms
     like the ugly crng_pre_init_inject().

   - The RNG no longer pretends to handle the "premature next" security
     model, something that various academics and other RNG designs have
     tried to care about in the past. After an interesting mailing list
     thread, these issues are thought to be a) mainly academic and not
     practical at all, and b) actively harming the real security of the
     RNG by delaying new entropy additions after a potential compromise,
     making a potentially bad situation even worse. As well, in the
     first place, our RNG never even properly handled the premature next
     issue, so removing an incomplete solution to a fake problem was
     particularly nice.

     This allowed for numerous other simplifications in the code, which
     is a lot cleaner as a consequence. If you didn't see it before,
     https://lore.kernel.org/lkml/[email protected]/ may be a
     thread worth skimming through.

   - While the interrupt handler received a separate code path years ago
     that avoids locks by using per-cpu data structures and a faster
     mixing algorithm, in order to reduce interrupt latency, input and
     disk events that are triggered in hardirq handlers were still
     hitting locks and more expensive algorithms. Those are now
     redirected to use the faster per-cpu data structures.

   - Rather than having the fake-crypto almost-siphash-based random32
     implementation be used right and left, and in many places where
     cryptographically secure randomness is desirable, the batched
     entropy code is now fast enough to replace that.

   - As usual, numerous code quality and documentation cleanups. For
     example, the initialization state machine now uses enum symbolic
     constants instead of just hard coding numbers everywhere.

   - Since the RNG initializes once, and then is always initialized
     thereafter, a pretty heavy amount of code used during that
     initialization is never used again. It is now completely cordoned
     off using static branches and it winds up in the .text.unlikely
     section so that it doesn't reduce cache compactness after the RNG
     is ready.

   - A variety of functions meant for waiting on the RNG to be
     initialized were only used by vsprintf, and in not a particularly
     optimal way. Replacing that usage with a more ordinary setup made
     it possible to remove those functions.

   - A cleanup of how we warn userspace about the use of uninitialized
     /dev/urandom and uninitialized get_random_bytes() usage.
     Interestingly, with the change you merged for 5.18 that attempts to
     use jitter (but does not block if it can't), the majority of users
     should never see those warnings for /dev/urandom at all now, and
     the one for in-kernel usage is mainly a debug thing.

   - The file_operations struct for /dev/[u]random now implements
     .read_iter and .write_iter instead of .read and .write, allowing it
     to also implement .splice_read and .splice_write, which makes
     splice(2) work again after it was broken here (and in many other
     places in the tree) during the set_fs() removal. This was a bit of
     a last minute arrival from Jens that hasn't had as much time to
     bake, so I'll be keeping my eye on this as well, but it seems
     fairly ordinary. Unfortunately, read_iter() is around 3% slower
     than read() in my tests, which I'm not thrilled about. But Jens and
     Al, spurred by this observation, seem to be making progress in
     removing the bottlenecks on the iter paths in the VFS layer in
     general, which should remove the performance gap for all drivers.

   - Assorted other bug fixes, cleanups, and optimizations.

   - A small SipHash cleanup"

* tag 'random-5.19-rc1-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/crng/random: (49 commits)
  random: check for signals after page of pool writes
  random: wire up fops->splice_{read,write}_iter()
  random: convert to using fops->write_iter()
  random: convert to using fops->read_iter()
  random: unify batched entropy implementations
  random: move randomize_page() into mm where it belongs
  random: remove mostly unused async readiness notifier
  random: remove get_random_bytes_arch() and add rng_has_arch_random()
  random: move initialization functions out of hot pages
  random: make consistent use of buf and len
  random: use proper return types on get_random_{int,long}_wait()
  random: remove extern from functions in header
  random: use static branch for crng_ready()
  random: credit architectural init the exact amount
  random: handle latent entropy and command line from random_init()
  random: use proper jiffies comparison macro
  random: remove ratelimiting for in-kernel unseeded randomness
  random: move initialization out of reseeding hot path
  random: avoid initializing twice in credit race
  random: use symbolic constants for crng_init states
  ...

1  2 
kernel/time/timekeeping.c
kernel/time/timer.c
lib/Kconfig.debug
net/core/dev.c

index 4ab9949772d52f23a9270cef821ddf4e623cd097,871c912860ed508505c1eef9a2af7fd050fba877..8e4b3c32fcf9d95911a8f26e3171d93759cb5949
@@@ -17,6 -17,7 +17,7 @@@
  #include <linux/clocksource.h>
  #include <linux/jiffies.h>
  #include <linux/time.h>
+ #include <linux/timex.h>
  #include <linux/tick.h>
  #include <linux/stop_machine.h>
  #include <linux/pvclock_gtod.h>
@@@ -429,14 -430,6 +430,14 @@@ static void update_fast_timekeeper(cons
        memcpy(base + 1, base, sizeof(*base));
  }
  
 +static __always_inline u64 fast_tk_get_delta_ns(struct tk_read_base *tkr)
 +{
 +      u64 delta, cycles = tk_clock_read(tkr);
 +
 +      delta = clocksource_delta(cycles, tkr->cycle_last, tkr->mask);
 +      return timekeeping_delta_to_ns(tkr, delta);
 +}
 +
  static __always_inline u64 __ktime_get_fast_ns(struct tk_fast *tkf)
  {
        struct tk_read_base *tkr;
                seq = raw_read_seqcount_latch(&tkf->seq);
                tkr = tkf->base + (seq & 0x01);
                now = ktime_to_ns(tkr->base);
 -
 -              now += timekeeping_delta_to_ns(tkr,
 -                              clocksource_delta(
 -                                      tk_clock_read(tkr),
 -                                      tkr->cycle_last,
 -                                      tkr->mask));
 +              now += fast_tk_get_delta_ns(tkr);
        } while (read_seqcount_latch_retry(&tkf->seq, seq));
  
        return now;
@@@ -531,27 -529,10 +532,27 @@@ u64 notrace ktime_get_boot_fast_ns(void
  {
        struct timekeeper *tk = &tk_core.timekeeper;
  
 -      return (ktime_get_mono_fast_ns() + ktime_to_ns(tk->offs_boot));
 +      return (ktime_get_mono_fast_ns() + ktime_to_ns(data_race(tk->offs_boot)));
  }
  EXPORT_SYMBOL_GPL(ktime_get_boot_fast_ns);
  
 +/**
 + * ktime_get_tai_fast_ns - NMI safe and fast access to tai clock.
 + *
 + * The same limitations as described for ktime_get_boot_fast_ns() apply. The
 + * mono time and the TAI offset are not read atomically which may yield wrong
 + * readouts. However, an update of the TAI offset is an rare event e.g., caused
 + * by settime or adjtimex with an offset. The user of this function has to deal
 + * with the possibility of wrong timestamps in post processing.
 + */
 +u64 notrace ktime_get_tai_fast_ns(void)
 +{
 +      struct timekeeper *tk = &tk_core.timekeeper;
 +
 +      return (ktime_get_mono_fast_ns() + ktime_to_ns(data_race(tk->offs_tai)));
 +}
 +EXPORT_SYMBOL_GPL(ktime_get_tai_fast_ns);
 +
  static __always_inline u64 __ktime_get_real_fast(struct tk_fast *tkf, u64 *mono)
  {
        struct tk_read_base *tkr;
                tkr = tkf->base + (seq & 0x01);
                basem = ktime_to_ns(tkr->base);
                baser = ktime_to_ns(tkr->base_real);
 -
 -              delta = timekeeping_delta_to_ns(tkr,
 -                              clocksource_delta(tk_clock_read(tkr),
 -                              tkr->cycle_last, tkr->mask));
 +              delta = fast_tk_get_delta_ns(tkr);
        } while (read_seqcount_latch_retry(&tkf->seq, seq));
  
        if (mono)
@@@ -2397,6 -2381,20 +2398,20 @@@ static int timekeeping_validate_timex(c
        return 0;
  }
  
+ /**
+  * random_get_entropy_fallback - Returns the raw clock source value,
+  * used by random.c for platforms with no valid random_get_entropy().
+  */
+ unsigned long random_get_entropy_fallback(void)
+ {
+       struct tk_read_base *tkr = &tk_core.timekeeper.tkr_mono;
+       struct clocksource *clock = READ_ONCE(tkr->clock);
+       if (unlikely(timekeeping_suspended || !clock))
+               return 0;
+       return clock->read(clock);
+ }
+ EXPORT_SYMBOL_GPL(random_get_entropy_fallback);
  
  /**
   * do_adjtimex() - Accessor function to NTP __do_adjtimex function
diff --combined kernel/time/timer.c
index a0666d948147684c59d694102eecb0fbb30faffa,c12fe329c9ff335f8846b14fb9ae1e8d6f8f461e..717fcb9fb14aa8306234b57aa4e45c466a3a720c
@@@ -44,7 -44,6 +44,7 @@@
  #include <linux/slab.h>
  #include <linux/compat.h>
  #include <linux/random.h>
 +#include <linux/sysctl.h>
  
  #include <linux/uaccess.h>
  #include <asm/unistd.h>
@@@ -224,7 -223,7 +224,7 @@@ static void timer_update_keys(struct wo
  static DECLARE_WORK(timer_update_work, timer_update_keys);
  
  #ifdef CONFIG_SMP
 -unsigned int sysctl_timer_migration = 1;
 +static unsigned int sysctl_timer_migration = 1;
  
  DEFINE_STATIC_KEY_FALSE(timers_migration_enabled);
  
@@@ -235,42 -234,7 +235,42 @@@ static void timers_update_migration(voi
        else
                static_branch_disable(&timers_migration_enabled);
  }
 -#else
 +
 +#ifdef CONFIG_SYSCTL
 +static int timer_migration_handler(struct ctl_table *table, int write,
 +                          void *buffer, size_t *lenp, loff_t *ppos)
 +{
 +      int ret;
 +
 +      mutex_lock(&timer_keys_mutex);
 +      ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
 +      if (!ret && write)
 +              timers_update_migration();
 +      mutex_unlock(&timer_keys_mutex);
 +      return ret;
 +}
 +
 +static struct ctl_table timer_sysctl[] = {
 +      {
 +              .procname       = "timer_migration",
 +              .data           = &sysctl_timer_migration,
 +              .maxlen         = sizeof(unsigned int),
 +              .mode           = 0644,
 +              .proc_handler   = timer_migration_handler,
 +              .extra1         = SYSCTL_ZERO,
 +              .extra2         = SYSCTL_ONE,
 +      },
 +      {}
 +};
 +
 +static int __init timer_sysctl_init(void)
 +{
 +      register_sysctl("kernel", timer_sysctl);
 +      return 0;
 +}
 +device_initcall(timer_sysctl_init);
 +#endif /* CONFIG_SYSCTL */
 +#else /* CONFIG_SMP */
  static inline void timers_update_migration(void) { }
  #endif /* !CONFIG_SMP */
  
@@@ -287,6 -251,19 +287,6 @@@ void timers_update_nohz(void
        schedule_work(&timer_update_work);
  }
  
 -int timer_migration_handler(struct ctl_table *table, int write,
 -                          void *buffer, size_t *lenp, loff_t *ppos)
 -{
 -      int ret;
 -
 -      mutex_lock(&timer_keys_mutex);
 -      ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
 -      if (!ret && write)
 -              timers_update_migration();
 -      mutex_unlock(&timer_keys_mutex);
 -      return ret;
 -}
 -
  static inline bool is_timers_nohz_active(void)
  {
        return static_branch_unlikely(&timers_nohz_active);
@@@ -525,7 -502,7 +525,7 @@@ static inline unsigned calc_index(unsig
         *
         * Round up with level granularity to prevent this.
         */
 -      expires = (expires + LVL_GRAN(lvl)) >> LVL_SHIFT(lvl);
 +      expires = (expires >> LVL_SHIFT(lvl)) + 1;
        *bucket_expiry = expires << LVL_SHIFT(lvl);
        return LVL_OFFS(lvl) + (expires & LVL_MASK);
  }
@@@ -638,39 -615,9 +638,39 @@@ static void internal_add_timer(struct t
  
  static const struct debug_obj_descr timer_debug_descr;
  
 +struct timer_hint {
 +      void    (*function)(struct timer_list *t);
 +      long    offset;
 +};
 +
 +#define TIMER_HINT(fn, container, timr, hintfn)                       \
 +      {                                                       \
 +              .function = fn,                                 \
 +              .offset   = offsetof(container, hintfn) -       \
 +                          offsetof(container, timr)           \
 +      }
 +
 +static const struct timer_hint timer_hints[] = {
 +      TIMER_HINT(delayed_work_timer_fn,
 +                 struct delayed_work, timer, work.func),
 +      TIMER_HINT(kthread_delayed_work_timer_fn,
 +                 struct kthread_delayed_work, timer, work.func),
 +};
 +
  static void *timer_debug_hint(void *addr)
  {
 -      return ((struct timer_list *) addr)->function;
 +      struct timer_list *timer = addr;
 +      int i;
 +
 +      for (i = 0; i < ARRAY_SIZE(timer_hints); i++) {
 +              if (timer_hints[i].function == timer->function) {
 +                      void (**fn)(void) = addr + timer_hints[i].offset;
 +
 +                      return *fn;
 +              }
 +      }
 +
 +      return timer->function;
  }
  
  static bool timer_is_static_object(void *addr)
@@@ -1833,8 -1780,6 +1833,6 @@@ void update_process_times(int user_tick
  {
        struct task_struct *p = current;
  
-       PRANDOM_ADD_NOISE(jiffies, user_tick, p, 0);
        /* Note: this timer irq context must be accounted for as well. */
        account_process_tick(p, user_tick);
        run_local_timers();
@@@ -2006,7 -1951,6 +2004,7 @@@ int timers_prepare_cpu(unsigned int cpu
                base = per_cpu_ptr(&timer_bases[b], cpu);
                base->clk = jiffies;
                base->next_expiry = base->clk + NEXT_TIMER_MAX_DELTA;
 +              base->next_expiry_recalc = false;
                base->timers_pending = false;
                base->is_idle = false;
        }
diff --combined lib/Kconfig.debug
index 55b9acb2f5246f4322f003524ef49fac4f8c519c,7e282970177a867670739d06c991da9cdfc5a833..a30d5279efda6fad5cd4165a00277554b802c7e3
@@@ -485,25 -485,24 +485,25 @@@ config FRAME_POINTE
          larger and slower, but it gives very useful debugging information
          in case of kernel bugs. (precise oopses/stacktraces/warnings)
  
 +config OBJTOOL
 +      bool
 +
  config STACK_VALIDATION
        bool "Compile-time stack metadata validation"
 -      depends on HAVE_STACK_VALIDATION
 +      depends on HAVE_STACK_VALIDATION && UNWINDER_FRAME_POINTER
 +      select OBJTOOL
        default n
        help
 -        Add compile-time checks to validate stack metadata, including frame
 -        pointers (if CONFIG_FRAME_POINTER is enabled).  This helps ensure
 -        that runtime stack traces are more reliable.
 -
 -        This is also a prerequisite for generation of ORC unwind data, which
 -        is needed for CONFIG_UNWINDER_ORC.
 +        Validate frame pointer rules at compile-time.  This helps ensure that
 +        runtime stack traces are more reliable.
  
          For more information, see
          tools/objtool/Documentation/stack-validation.txt.
  
 -config VMLINUX_VALIDATION
 +config NOINSTR_VALIDATION
        bool
 -      depends on STACK_VALIDATION && DEBUG_ENTRY
 +      depends on HAVE_NOINSTR_VALIDATION && DEBUG_ENTRY
 +      select OBJTOOL
        default y
  
  config VMLINUX_MAP
@@@ -1617,8 -1616,7 +1617,7 @@@ config WARN_ALL_UNSEEDED_RANDO
          so architecture maintainers really need to do what they can
          to get the CRNG seeded sooner after the system is booted.
          However, since users cannot do anything actionable to
-         address this, by default the kernel will issue only a single
-         warning for the first use of unseeded randomness.
+         address this, by default this option is disabled.
  
          Say Y here if you want to receive warnings for all uses of
          unseeded randomness.  This will be of use primarily for
@@@ -2036,11 -2034,10 +2035,11 @@@ config KCO
        bool "Code coverage for fuzzing"
        depends on ARCH_HAS_KCOV
        depends on CC_HAS_SANCOV_TRACE_PC || GCC_PLUGINS
 -      depends on !ARCH_WANTS_NO_INSTR || STACK_VALIDATION || \
 +      depends on !ARCH_WANTS_NO_INSTR || HAVE_NOINSTR_HACK || \
                   GCC_VERSION >= 120000 || CLANG_VERSION >= 130000
        select DEBUG_FS
        select GCC_PLUGIN_SANCOV if !CC_HAS_SANCOV_TRACE_PC
 +      select OBJTOOL if HAVE_NOINSTR_HACK
        help
          KCOV exposes kernel code coverage information in a form suitable
          for coverage-guided fuzzing (randomized testing).
diff --combined net/core/dev.c
index 2771fd22dc6aedd0cd82bad91983f6d2381b451d,19c9beb1136bd155d9e6e8296ed13e16274466b6..191ec76d4c3b3a72bd216b1027087234790adf07
@@@ -681,11 -681,11 +681,11 @@@ int dev_fill_forward_path(const struct 
        const struct net_device *last_dev;
        struct net_device_path_ctx ctx = {
                .dev    = dev,
 -              .daddr  = daddr,
        };
        struct net_device_path *path;
        int ret = 0;
  
 +      memcpy(ctx.daddr, daddr, sizeof(ctx.daddr));
        stack->num_paths = 0;
        while (ctx.dev && ctx.dev->netdev_ops->ndo_fill_forward_path) {
                last_dev = ctx.dev;
@@@ -3527,7 -3527,6 +3527,6 @@@ static int xmit_one(struct sk_buff *skb
                dev_queue_xmit_nit(skb, dev);
  
        len = skb->len;
-       PRANDOM_ADD_NOISE(skb, dev, txq, len + jiffies);
        trace_net_dev_start_xmit(skb, dev);
        rc = netdev_start_xmit(skb, dev, txq, more);
        trace_net_dev_xmit(skb, rc, dev, len);
@@@ -4168,7 -4167,6 +4167,6 @@@ static int __dev_queue_xmit(struct sk_b
                        if (!skb)
                                goto out;
  
-                       PRANDOM_ADD_NOISE(skb, dev, txq, jiffies);
                        HARD_TX_LOCK(dev, txq, cpu);
  
                        if (!netif_xmit_stopped(txq)) {
@@@ -4234,7 -4232,6 +4232,6 @@@ int __dev_direct_xmit(struct sk_buff *s
  
        skb_set_queue_mapping(skb, queue_id);
        txq = skb_get_tx_queue(dev, skb);
-       PRANDOM_ADD_NOISE(skb, dev, txq, jiffies);
  
        local_bh_disable();
  
This page took 0.102049 seconds and 4 git commands to generate.