Hi,

Thanks for clarifying our confusion and we are sorry if we caused any trouble.

> On Nov 30, 2020, at 10:53 AM, Florian Westphal <f...@strlen.de> wrote:
> 
> Gong, Sishuai <sish...@purdue.edu> wrote:
>> Hi,
>> 
>> We found a data race in linux kernel 5.3.11 that we are able to reproduce in 
>> x86 under specific interleavings. We are not sure about the consequence of 
>> this race now but it seems that the two memcpy() can lead to some 
>> inconsistency. We also noticed that both the writer and reader are protected 
>> by locks, but the writer is protected using seqlock while the reader is 
>> protected by rculock.
> 
> AFAICS reader uses same seqlock as the writer.
> 
>> ------------------------------------------
>> Write site
>> 
>> /tmp/tmp.B7zb7od2zE-5.3.11/extract/linux-5.3.11/net/ethernet/eth.c:264
>>        252  /**
>>        253   * eth_header_cache_update - update cache entry
>>        254   * @hh: destination cache entry
>>        255   * @dev: network device
>>        256   * @haddr: new hardware address
>>        257   *
>>        258   * Called by Address Resolution module to notify changes in 
>> address.
>>        259   */
>>        260  void eth_header_cache_update(struct hh_cache *hh,
>>        261                   const struct net_device *dev,
>>        262                   const unsigned char *haddr)
>>        263  {
>> ==>    264      memcpy(((u8 *) hh->hh_data) + HH_DATA_OFF(sizeof(struct 
>> ethhdr)),
>>        265             haddr, ETH_ALEN);
> 
> This is called under write_seqlock_bh(hh->hh_lock)
> 
>> /tmp/tmp.B7zb7od2zE-5.3.11/extract/linux-5.3.11/include/net/neighbour.h:481
>>        463  static inline int neigh_hh_output(const struct hh_cache *hh, 
>> struct sk_buff *skb)
>>        464  {
>>        465      unsigned int hh_alen = 0;
>>        466      unsigned int seq;
>>        467      unsigned int hh_len;
>>        468
>>        469      do {
>>        470          seq = read_seqbegin(&hh->hh_lock); 
> 
> This samples the seqcount.
> 
>>        471          hh_len = hh->hh_len;
>>        472          if (likely(hh_len <= HH_DATA_MOD)) {
>>        473              hh_alen = HH_DATA_MOD;
>>        474
>>        475              /* skb_push() would proceed silently if we have room 
>> for
>>        476               * the unaligned size but not for the aligned size:
>>        477               * check headroom explicitly.
>>        478               */
>>        479              if (likely(skb_headroom(skb) >= HH_DATA_MOD)) {
>>        480                  /* this is inlined by gcc */
>> ==>    481                  memcpy(skb->data - HH_DATA_MOD, hh->hh_data,
>>        482                         HH_DATA_MOD);
> 
> [..]
> 
>>        492      } while (read_seqretry(&hh->hh_lock, seq));
> 
> ... so this retries unless seqcount was stable.

Reply via email to