NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: lib/25367: arc4random state is shared across forks



The following reply was made to PR lib/25367; it has been noted by GNATS.

From: David Holland <dholland-bugs%netbsd.org@localhost>
To: gnats-bugs%netbsd.org@localhost
Cc: 
Subject: Re: lib/25367: arc4random state is shared across forks
Date: Fri, 30 May 2014 08:19:43 +0000

 here's another copy of the mail above (that got sent to the wrong
 place) in which the patch isn't base64'd:
 
    ------
 
 From: Roy Marples <roy%marples.name@localhost>
 To: gnats%netbsd.org@localhost
 Subject: Re: lib/25367: arc4random state is shared across forks
 Date: Sat, 24 May 2014 23:07:07 +0100
 
 Hi
 
 I bumped into this as well.
 I looked over the FreeBSD thread regarding potential speed issues and despite
 any concerns they have actually merged the change in.
 Attached is a patch to -current which does two things.
 
 1) Re-stirs if the pid changes
 2) Re-stirs after swallowing 1600000 bytes (which also addresses PR/45952)
 
 I've been running this on my laptop for a while with great success and unless
 anyone objects I'll commit it shortly.
 
 Thanks
 
 Roy
 
 ? test
 ? test.c
 Index: gen/arc4random.c
 ===================================================================
 RCS file: /cvsroot/src/lib/libc/gen/arc4random.c,v
 retrieving revision 1.21
 diff -u -p -r1.21 arc4random.c
 --- gen/arc4random.c   17 Oct 2013 23:56:17 -0000      1.21
 +++ gen/arc4random.c   24 May 2014 21:40:13 -0000
 @@ -49,11 +49,11 @@ __weak_alias(arc4random_uniform,_arc4ran
  #endif
  
  struct arc4_stream {
 -      uint8_t stirred;
 -      uint8_t pad;
        uint8_t i;
        uint8_t j;
        uint8_t s[(uint8_t)~0u + 1u];   /* 256 to you and me */
 +      size_t count;
 +      pid_t stir_pid;
        mutex_t mtx;
  };
  
 @@ -67,7 +67,7 @@ struct arc4_stream {
                        mutex_unlock(&(rs)->mtx);      \
        }
  #else
 -#define LOCK(rs) 
 +#define LOCK(rs)
  #define UNLOCK(rs)
  #endif
  
 @@ -78,7 +78,7 @@ struct arc4_stream {
  #define S256 S64(0), S64(64), S64(128), S64(192)
  
  static struct arc4_stream rs = { .i = 0xff, .j = 0, .s = { S256 },
 -              .stirred = 0, .mtx = MUTEX_INITIALIZER };
 +              .count = 0, .stir_pid = 0, .mtx = MUTEX_INITIALIZER };
  
  #undef S
  #undef S4
 @@ -87,20 +87,10 @@ static struct arc4_stream rs = { .i = 0x
  #undef S256
  
  static inline void arc4_addrandom(struct arc4_stream *, u_char *, int);
 -static __noinline void arc4_stir(struct arc4_stream *);
 +static __noinline void arc4_stir(struct arc4_stream *, pid_t);
  static inline uint8_t arc4_getbyte(struct arc4_stream *);
  static inline uint32_t arc4_getword(struct arc4_stream *);
  
 -static inline int
 -arc4_check_init(struct arc4_stream *as)
 -{
 -      if (__predict_true(rs.stirred))
 -              return 0;
 -
 -      arc4_stir(as);
 -      return 1;
 -}
 -
  static inline void
  arc4_addrandom(struct arc4_stream *as, u_char *dat, int datlen)
  {
 @@ -117,7 +107,7 @@ arc4_addrandom(struct arc4_stream *as, u
  }
  
  static __noinline void
 -arc4_stir(struct arc4_stream *as)
 +arc4_stir(struct arc4_stream *as, pid_t pid)
  {
        int rdat[32];
        int mib[] = { CTL_KERN, KERN_URND };
 @@ -146,10 +136,24 @@ arc4_stir(struct arc4_stream *as)
         * paper "Weaknesses in the Key Scheduling Algorithm of RC4"
         * by Fluher, Mantin, and Shamir.  (N = 256 in our case.)
         */
 -      for (j = 0; j < __arraycount(as->s) * 4; j++)
 +      for (j = 0; j < __arraycount(as->s) * sizeof(uint32_t); j++)
                arc4_getbyte(as);
  
 -      as->stirred = 1;
 +      /* Stir again after swallowing 1600000 bytes or if the pid changes */
 +      as->count = 1600000;
 +      as->stir_pid = pid;
 +}
 +
 +static inline void
 +arc4_stir_if_needed(struct arc4_stream *as, size_t len)
 +{
 +      pid_t pid;
 +
 +      pid = getpid();
 +      if (as->count <= len || as->stir_pid != pid)
 +              arc4_stir(as, pid);
 +      else
 +              as->count -= len;
  }
  
  static __inline uint8_t
 @@ -169,6 +173,7 @@ arc4_getbyte_ij(struct arc4_stream *as, 
  static inline uint8_t
  arc4_getbyte(struct arc4_stream *as)
  {
 +
        return arc4_getbyte_ij(as, &as->i, &as->j);
  }
  
 @@ -176,6 +181,7 @@ static inline uint32_t
  arc4_getword(struct arc4_stream *as)
  {
        uint32_t val;
 +
        val = arc4_getbyte(as) << 24;
        val |= arc4_getbyte(as) << 16;
        val |= arc4_getbyte(as) << 8;
 @@ -186,16 +192,18 @@ arc4_getword(struct arc4_stream *as)
  void
  arc4random_stir(void)
  {
 +
        LOCK(&rs);
 -      arc4_stir(&rs);
 +      arc4_stir(&rs, getpid());
        UNLOCK(&rs);
  }
  
  void
  arc4random_addrandom(u_char *dat, int datlen)
  {
 +
        LOCK(&rs);
 -      arc4_check_init(&rs);
 +      arc4_stir_if_needed(&rs, datlen);
        arc4_addrandom(&rs, dat, datlen);
        UNLOCK(&rs);
  }
 @@ -206,7 +214,7 @@ arc4random(void)
        uint32_t v;
  
        LOCK(&rs);
 -      arc4_check_init(&rs);
 +      arc4_stir_if_needed(&rs, sizeof(v));
        v = arc4_getword(&rs);
        UNLOCK(&rs);
        return v;
 @@ -220,7 +228,7 @@ arc4random_buf(void *buf, size_t len)
        uint8_t i, j;
  
        LOCK(&rs);
 -      arc4_check_init(&rs);
 +      arc4_stir_if_needed(&rs, len);
  
        /* cache i and j - compiler can't know 'buf' doesn't alias them */
        i = rs.i;
 @@ -263,7 +271,7 @@ arc4random_uniform(uint32_t upper_bound)
        min = (0xFFFFFFFFU - upper_bound + 1) % upper_bound;
  
        LOCK(&rs);
 -      arc4_check_init(&rs);
 +      arc4_stir_if_needed(&rs, sizeof(r));
  
        /*
         * This could theoretically loop forever but each retry has
 


Home | Main Index | Thread Index | Old Index