lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <201010292223.IIF64065.tOLVFJFSQOMFOH@I-love.SAKURA.ne.jp>
Date:	Fri, 29 Oct 2010 22:23:41 +0900
From:	Tetsuo Handa <penguin-kernel@...ove.SAKURA.ne.jp>
To:	paulmck@...ux.vnet.ibm.com
Cc:	linux-kernel@...r.kernel.org
Subject: Memory barrier question.

Hello.

I got a question regarding memory barrier.

sruct word {
	struct list_head list;
	char *buf;
};

static LIST_HEAD(wordlist);
static DEFINE_SPINLOCK(wordlist_lock);

--- On CPU 0 ---

struct word *hello = kzalloc(sizeof(*hello), GFP_KERNEL);
hello->buf = kstrdup("hello", GFP_KERNEL);
spin_lock(&wordlist_lock);
list_add_rcu(&hello.list, &wordlist);
spin_unlock(&wordlist_lock);

--- On CPU 1 ---

struct word *ptr;
rcu_read_lock();
list_for_each_entry_rcu(ptr, &wordlist, list) {
	char *str = ptr->buf;
	printk("%s\n", str);
}
rcu_read_unlock();

Use of rcu_assign_pointer() and rcu_dereference() guarantees that
CPU 1 gets &hello->list by reading wordlist.next only after
CPU 1 can get kstrdup()ed pointer by reading hello->buf.
But what guarantees that CPU 1 gets "hello" by reading kstrdup()ed pointer?

Say, kstrdup("hello", GFP_KERNEL) stores

  'h' -> 0xC0000000
  'e' -> 0xC0000001
  'l' -> 0xC0000002
  'l' -> 0xC0000003
  'o' -> 0xC0000004
  '\0' -> 0xC0000005

and hello->buf = kstrdup() stores

  0xC0000000 -> hello->buf

.

If ordered by smp_wmb() by CPU 0 and smp_rmb() by CPU 1,
str = ptr->buf will load

  0xC0000000 -> str

and printk("%s\n", str) will load

  0xC0000000 -> 'h'
  0xC0000001 -> 'e'
  0xC0000002 -> 'l'
  0xC0000003 -> 'l'
  0xC0000004 -> 'o'
  0xC0000005 -> '\0'

.

Since CPU 0 issued smp_wmb() (inside list_add_rcu()) but CPU 1 did not issue
smp_rmb() (inside list_for_each_entry_rcu()), I think CPU 1 would see bogus
values like

  0xC0000000 -> 'h'
  0xC0000001 -> 'a'
  0xC0000002 -> 'l'
  0xC0000003 -> '1'
  0xC0000004 -> 'o'
  0xC0000005 -> 'w'
  0xC0000006 -> 'e'
  0xC0000007 -> 'e'
  0xC0000008 -> 'n'
  0xC0000009 -> '\0'

.

It seems to me that people do not call smp_rmb() before reading memory
which was dynamically allocated/initialized. What am I missing?

Regards.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ