public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [TOMOYO 0/2] Final patches for kenrel 2.6.30.
@ 2009-04-08 13:31 Tetsuo Handa
  2009-04-08 13:31 ` [TOMOYO 1/2] tomoyo: add Documentation/tomoyo.txt Tetsuo Handa
  2009-04-08 13:31 ` [TOMOYO 2/2] Hello Tetsuo Handa
  0 siblings, 2 replies; 34+ messages in thread
From: Tetsuo Handa @ 2009-04-08 13:31 UTC (permalink / raw)
  To: jmorris; +Cc: linux-security-module, linux-kernel

TOMOYO Linux was merged into the mainline in 2.6.29-git1.

We thank Satoru Ueda for giving us opportunities to have presentations at CE
Linux Forum's Japan Technical Jamboree. This was the first event that we were
taught what the mainline is.

We thank Hirotaka Yoshioka for giving us opportunities to have presentations at
YLUG kernel code reading party. This was the very event that we were
foreordained to challenge the mainline. Without this event, we would not have
started the challenge for the mainline.

We thank James Morris for coming to Linux Foundation Japan Symposium #8 and
Linux Conf Au 2009 and understanding why name based security is needed.

We thank Casey Schaufler for proving that new security modules can merge into
the mainline.

We thank Stephen Smalley for coming to Ottawa Linux Symposium 2007/2008 and
giving us a critical comment that extricated ourselves from our stagnation.

We thank Andrew Morton for listening to our problem when we were blocked by
the lack of new LSM hooks.

We thank Al Viro for accepting new LSM hooks which made TOMOYO possible to
merge into the mainline.

We thank Crispin Cowan for proposing AppArmor. We were able to have a chance to
understand why name based security is regarded as an inferior solution.
We continued the name based security, with our belief that inode based security
and name based security are complementary and both should be used together.
The gate for name based security opened. Go for it!

We thank Turbolinux for adopting TOMOYO into Turbolinux's products.

We thank Mandriva Linux for adopting TOMOYO into Mandriva Linux's products.

We thank Hideaki Yoshifuji for giving us advices on how to negotiate.

We thank Motohiro Kosaki for giving us advices on how to write patch comments.

We thank Fumihito Yoshida for supporting TOMOYO in Ubuntu.

We thank Hideki Yamane for supporting TOMOYO in Debian.

We thank Naohiro Aota for supporting TOMOYO in Gentoo.

We thank Ken-ichi Akimoto for supporting TOMOYO in Natures Linux.

We thank Vadim Korschok for using TOMOYO on Hardened Gentoo.

We thank Hiroshi Shinji for using TOMOYO on embedded systems and
requesting new features and helping debugging.

We thank Toru Hirasaka for developing TOMOYO's GUI policy editor.

We thank Yoshihiro Kusuno for enhancing TOMOYO's CUI policy editor.

We thank Masafumi Tanaka for drawing posters and developing demonstration
movies.

We thank Akira Igarashi for drawing TOMOYO's logo and drawing many
illustrations for presentations.

We thank Kohei Kaigai for coordinating various open source events.

We thank Japan Secure Operating System Users Group for giving us opportunities
to familiarize SELinux, TOMOYO, AppArmor, LIDS etc. in Japan.

We thank anonymous users giving us suggestions and comments and feature
requests on 2ch.net and sourceforge.jp and blogs. TOMOYO achieved 30,000
downloads since the release of TOMOYO Linux version 1.0 on 2005/11/11.

We thank Dragos Ruiu for giving us opportunities to have presentations at
PacSec conference 2007/2008.

We thank Jonathan Corbet for writing many articles on TOMOYO at LWN.net ever
since Embedded Linux Conference 2007.

We thank CLAMP for creating Card Captor Sakura. TOMOYO's idea was taken from
the Sakura's happy world.

We thank SourceForge.jp for providing us storages and services.

We thank NTT DATA CORPORATION for supporting us in development of TOMOYO.

We thank Linus Torvalds for allowing us to join the Linux community.

With many more thanks, we would like to release this snapshot as TOMOYO Linux
version 2.2.0. Thank you for waiting.

--
Kentaro Takeda
Tetsuo Handa
Toshiharu Harada


^ permalink raw reply	[flat|nested] 34+ messages in thread

* [TOMOYO 1/2] tomoyo: add Documentation/tomoyo.txt
  2009-04-08 13:31 [TOMOYO 0/2] Final patches for kenrel 2.6.30 Tetsuo Handa
@ 2009-04-08 13:31 ` Tetsuo Handa
  2009-04-10 12:26   ` Peter Dolding
  2009-04-10 17:10   ` Pavel Machek
  2009-04-08 13:31 ` [TOMOYO 2/2] Hello Tetsuo Handa
  1 sibling, 2 replies; 34+ messages in thread
From: Tetsuo Handa @ 2009-04-08 13:31 UTC (permalink / raw)
  To: jmorris
  Cc: linux-security-module, linux-kernel, Kentaro Takeda, Tetsuo Handa,
	Toshiharu Harada

[-- Attachment #1: tomoyo-documentation.patch --]
[-- Type: text/plain, Size: 2567 bytes --]

Signed-off-by: Kentaro Takeda <takedakn@nttdata.co.jp>
Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Signed-off-by: Toshiharu Harada <haradats@nttdata.co.jp>
---
 Documentation/tomoyo.txt |   52 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 52 insertions(+)

--- /dev/null
+++ linux-2.6.30-rc1/Documentation/tomoyo.txt
@@ -0,0 +1,52 @@
+--- What is TOMOYO? ---
+
+TOMOYO is a name-based MAC extension (LSM module) for the Linux kernel.
+
+LiveCD-based tutorials are available at
+http://tomoyo.sourceforge.jp/en/1.6.x/1st-step/ubuntu8.04-live/
+http://tomoyo.sourceforge.jp/en/1.6.x/1st-step/centos5-live/ .
+Though these tutorials use non-LSM version of TOMOYO, they are useful for you
+to know what TOMOYO is.
+
+--- How to enable TOMOYO? ---
+
+Build the kernel with CONFIG_SECURITY_TOMOYO=y and pass "security=tomoyo" to
+kernel's command line.
+
+Please see http://tomoyo.sourceforge.jp/en/2.2.x/ for details.
+
+--- Where are documentations? ---
+
+Materials we prepared for seminars and symposiums are available at
+http://sourceforge.jp/projects/tomoyo/docs/?category_id=532&language_id=1 .
+Below lists are chosen from three aspects.
+
+What is TOMOYO?
+  TOMOYO Linux Overview
+    http://sourceforge.jp/projects/tomoyo/docs/lca2009-takeda.pdf
+  TOMOYO Linux: pragmatic and manageable security for Linux
+    http://sourceforge.jp/projects/tomoyo/docs/freedomhectaipei-tomoyo.pdf
+  TOMOYO Linux: A Practical Method to Understand and Protect Your Own Linux Box
+    http://sourceforge.jp/projects/tomoyo/docs/PacSec2007-en-no-demo.pdf
+
+What can TOMOYO do?
+  Deep inside TOMOYO Linux
+    http://sourceforge.jp/projects/tomoyo/docs/lca2009-kumaneko.pdf
+  The role of "pathname based access control" in security.
+    http://sourceforge.jp/projects/tomoyo/docs/lfj2008-bof.pdf
+
+History of TOMOYO?
+  Realities of Mainlining
+    http://sourceforge.jp/projects/tomoyo/docs/lfj2008.pdf
+
+--- What is future plan? ---
+
+We believe that inode based security and name based security are complementary
+and both should be used together. But unfortunately, so far, we cannot enable
+multiple LSM modules at the same time. We feel sorry that you have to give up
+SELinux/SMACK/AppArmor etc. when you want to use TOMOYO.
+
+We hope that LSM becomes stackable in future. Meanwhile, you can use non-LSM
+version of TOMOYO, available at http://tomoyo.sourceforge.jp/en/1.6.x/ .
+LSM version of TOMOYO is a subset of non-LSM version of TOMOYO. We are planning
+to port non-LSM version's functionalities to LSM versions.

-- 

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [TOMOYO 2/2] Hello.
  2009-04-08 13:31 [TOMOYO 0/2] Final patches for kenrel 2.6.30 Tetsuo Handa
  2009-04-08 13:31 ` [TOMOYO 1/2] tomoyo: add Documentation/tomoyo.txt Tetsuo Handa
@ 2009-04-08 13:31 ` Tetsuo Handa
  2009-04-10 11:55   ` Tetsuo Handa
  1 sibling, 1 reply; 34+ messages in thread
From: Tetsuo Handa @ 2009-04-08 13:31 UTC (permalink / raw)
  To: jmorris
  Cc: linux-security-module, linux-kernel, Kentaro Takeda, Tetsuo Handa,
	Toshiharu Harada

[-- Attachment #1: tomoyo-version-bump.patch --]
[-- Type: text/plain, Size: 6902 bytes --]

TOMOYO Linux was merged into the mainline in 2.6.29-git1.

We thank Satoru Ueda for giving us opportunities to have presentations at CE
Linux Forum's Japan Technical Jamboree. This was the first event that we were
taught what the mainline is.

We thank Hirotaka Yoshioka for giving us opportunities to have presentations at
YLUG kernel code reading party. This was the very event that we were
foreordained to challenge the mainline. Without this event, we would not have
started the challenge for the mainline.

We thank James Morris for coming to Linux Foundation Japan Symposium #8 and
Linux Conf Au 2009 and understanding why name based security is needed.

We thank Casey Schaufler for proving that new security modules can merge into
the mainline.

We thank Stephen Smalley for coming to Ottawa Linux Symposium 2007/2008 and
giving us a critical comment that extricated ourselves from our stagnation.

We thank Andrew Morton for listening to our problem when we were blocked by
the lack of new LSM hooks.

We thank Al Viro for accepting new LSM hooks which made TOMOYO possible to
merge into the mainline.

We thank Crispin Cowan for proposing AppArmor. We were able to have a chance to
understand why name based security is regarded as an inferior solution.
We continued the name based security, with our belief that inode based security
and name based security are complementary and both should be used together.
The gate for name based security opened. Go for it!

We thank Turbolinux for adopting TOMOYO into Turbolinux's products.

We thank Mandriva Linux for adopting TOMOYO into Mandriva Linux's products.

We thank Hideaki Yoshifuji for giving us advices on how to negotiate.

We thank Motohiro Kosaki for giving us advices on how to write patch comments.

We thank Fumihito Yoshida for supporting TOMOYO in Ubuntu.

We thank Hideki Yamane for supporting TOMOYO in Debian.

We thank Naohiro Aota for supporting TOMOYO in Gentoo.

We thank Ken-ichi Akimoto for supporting TOMOYO in Natures Linux.

We thank Vadim Korschok for using TOMOYO on Hardened Gentoo.

We thank Hiroshi Shinji for using TOMOYO on embedded systems and
requesting new features and helping debugging.

We thank Toru Hirasaka for developing TOMOYO's GUI policy editor.

We thank Yoshihiro Kusuno for enhancing TOMOYO's CUI policy editor.

We thank Masafumi Tanaka for drawing posters and developing demonstration
movies.

We thank Akira Igarashi for drawing TOMOYO's logo and drawing many
illustrations for presentations.

We thank Kohei Kaigai for coordinating various open source events.

We thank Japan Secure Operating System Users Group for giving us opportunities
to familiarize SELinux, TOMOYO, AppArmor, LIDS etc. in Japan.

We thank anonymous users giving us suggestions and comments and feature
requests on 2ch.net and sourceforge.jp and blogs. TOMOYO achieved 30,000
downloads since the release of TOMOYO Linux version 1.0 on 2005/11/11.

We thank Dragos Ruiu for giving us opportunities to have presentations at
PacSec conference 2007/2008.

We thank Jonathan Corbet for writing many articles on TOMOYO at LWN.net ever
since Embedded Linux Conference 2007.

We thank CLAMP for creating Card Captor Sakura. TOMOYO's idea was taken from
the Sakura's happy world.

We thank SourceForge.jp for providing us storages and services.

We thank NTT DATA CORPORATION for supporting us in development of TOMOYO.

We thank Linus Torvalds for allowing us to join the Linux community.

With many more thanks, we would like to release this snapshot as TOMOYO Linux
version 2.2.0. Thank you for waiting.
----------------------------------------
Subject: [TOMOYO 2/2] tomoyo: version bump to 2.2.0.

Signed-off-by: Kentaro Takeda <takedakn@nttdata.co.jp>
Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Signed-off-by: Toshiharu Harada <haradats@nttdata.co.jp>
---
 security/tomoyo/common.c   |    6 +++---
 security/tomoyo/common.h   |    2 +-
 security/tomoyo/domain.c   |    2 +-
 security/tomoyo/file.c     |    2 +-
 security/tomoyo/realpath.c |    2 +-
 security/tomoyo/realpath.h |    2 +-
 security/tomoyo/tomoyo.c   |    2 +-
 security/tomoyo/tomoyo.h   |    2 +-
 8 files changed, 10 insertions(+), 10 deletions(-)

--- linux-2.6.30-rc1.orig/security/tomoyo/common.c
+++ linux-2.6.30-rc1/security/tomoyo/common.c
@@ -5,7 +5,7 @@
  *
  * Copyright (C) 2005-2009  NTT DATA CORPORATION
  *
- * Version: 2.2.0-pre   2009/02/01
+ * Version: 2.2.0   2009/04/01
  *
  */
 
@@ -1773,7 +1773,7 @@ void tomoyo_load_policy(const char *file
 	envp[2] = NULL;
 	call_usermodehelper(argv[0], argv, envp, 1);
 
-	printk(KERN_INFO "TOMOYO: 2.2.0-pre   2009/02/01\n");
+	printk(KERN_INFO "TOMOYO: 2.2.0   2009/04/01\n");
 	printk(KERN_INFO "Mandatory Access Control activated.\n");
 	tomoyo_policy_loaded = true;
 	{ /* Check all profiles currently assigned to domains are defined. */
@@ -1800,7 +1800,7 @@ void tomoyo_load_policy(const char *file
 static int tomoyo_read_version(struct tomoyo_io_buffer *head)
 {
 	if (!head->read_eof) {
-		tomoyo_io_printf(head, "2.2.0-pre");
+		tomoyo_io_printf(head, "2.2.0");
 		head->read_eof = true;
 	}
 	return 0;
--- linux-2.6.30-rc1.orig/security/tomoyo/common.h
+++ linux-2.6.30-rc1/security/tomoyo/common.h
@@ -5,7 +5,7 @@
  *
  * Copyright (C) 2005-2009  NTT DATA CORPORATION
  *
- * Version: 2.2.0-pre   2009/02/01
+ * Version: 2.2.0   2009/04/01
  *
  */
 
--- linux-2.6.30-rc1.orig/security/tomoyo/domain.c
+++ linux-2.6.30-rc1/security/tomoyo/domain.c
@@ -5,7 +5,7 @@
  *
  * Copyright (C) 2005-2009  NTT DATA CORPORATION
  *
- * Version: 2.2.0-pre   2009/02/01
+ * Version: 2.2.0   2009/04/01
  *
  */
 
--- linux-2.6.30-rc1.orig/security/tomoyo/file.c
+++ linux-2.6.30-rc1/security/tomoyo/file.c
@@ -5,7 +5,7 @@
  *
  * Copyright (C) 2005-2009  NTT DATA CORPORATION
  *
- * Version: 2.2.0-pre   2009/02/01
+ * Version: 2.2.0   2009/04/01
  *
  */
 
--- linux-2.6.30-rc1.orig/security/tomoyo/realpath.c
+++ linux-2.6.30-rc1/security/tomoyo/realpath.c
@@ -5,7 +5,7 @@
  *
  * Copyright (C) 2005-2009  NTT DATA CORPORATION
  *
- * Version: 2.2.0-pre   2009/02/01
+ * Version: 2.2.0   2009/04/01
  *
  */
 
--- linux-2.6.30-rc1.orig/security/tomoyo/realpath.h
+++ linux-2.6.30-rc1/security/tomoyo/realpath.h
@@ -5,7 +5,7 @@
  *
  * Copyright (C) 2005-2009  NTT DATA CORPORATION
  *
- * Version: 2.2.0-pre   2009/02/01
+ * Version: 2.2.0   2009/04/01
  *
  */
 
--- linux-2.6.30-rc1.orig/security/tomoyo/tomoyo.c
+++ linux-2.6.30-rc1/security/tomoyo/tomoyo.c
@@ -5,7 +5,7 @@
  *
  * Copyright (C) 2005-2009  NTT DATA CORPORATION
  *
- * Version: 2.2.0-pre   2009/02/01
+ * Version: 2.2.0   2009/04/01
  *
  */
 
--- linux-2.6.30-rc1.orig/security/tomoyo/tomoyo.h
+++ linux-2.6.30-rc1/security/tomoyo/tomoyo.h
@@ -5,7 +5,7 @@
  *
  * Copyright (C) 2005-2009  NTT DATA CORPORATION
  *
- * Version: 2.2.0-pre   2009/02/01
+ * Version: 2.2.0   2009/04/01
  *
  */
 

-- 

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [TOMOYO 2/2] Hello.
  2009-04-08 13:31 ` [TOMOYO 2/2] Hello Tetsuo Handa
@ 2009-04-10 11:55   ` Tetsuo Handa
  0 siblings, 0 replies; 34+ messages in thread
From: Tetsuo Handa @ 2009-04-10 11:55 UTC (permalink / raw)
  To: jmorris; +Cc: linux-security-module, linux-kernel

I forgot to save the file. Sorry for duplicated text.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [TOMOYO 1/2] tomoyo: add Documentation/tomoyo.txt
  2009-04-08 13:31 ` [TOMOYO 1/2] tomoyo: add Documentation/tomoyo.txt Tetsuo Handa
@ 2009-04-10 12:26   ` Peter Dolding
  2009-04-10 17:10   ` Pavel Machek
  1 sibling, 0 replies; 34+ messages in thread
From: Peter Dolding @ 2009-04-10 12:26 UTC (permalink / raw)
  To: Tetsuo Handa
  Cc: jmorris, linux-security-module, linux-kernel, Kentaro Takeda,
	Toshiharu Harada

> +
> +We believe that inode based security and name based security are complementary
> +and both should be used together. But unfortunately, so far, we cannot enable
> +multiple LSM modules at the same time. We feel sorry that you have to give up
> +SELinux/SMACK/AppArmor etc. when you want to use TOMOYO.
> +
> +We hope that LSM becomes stackable in future. Meanwhile, you can use non-LSM
> +version of TOMOYO, available at http://tomoyo.sourceforge.jp/en/1.6.x/ .
> +LSM version of TOMOYO is a subset of non-LSM version of TOMOYO. We are planning
> +to port non-LSM version's functionalities to LSM versions.
>
If you go back through the mailing list you will find stackable has
been debated at length many times.

AppArmor and Tomoyo are both name based.  So unlikely you would want
both at the same time.

LSM exists mostly because designers of security systems could not
decide on the 1 default Linux should have.

For inode and name based security the question should be can Tomoyo
merge with the other LSM modules in away that avoids stacking.

Smack and Selinux are sharing code in places with each other.   Really
there are only 3 currently active developed LSM's Smack Selinux and
Tomoyo.  Merge could basically get us down to 1 with 3 different
configure processing engines.   I have not seen apparmor patches that
bring it up to using the secure way of doing name based secuirty.
Could have missed it.

Smack and Selinux both have not contained name based because there was
no secure way todo it.  Due to Tomoyo teams work that has changed.  So
both Smack and Selinux really need to look at there position on
supporting name based.  I agree it would be a gain of Smack and
Selinux supported name based.

Major reason for not allowing multi-able LSM's is the risk that one
might interfere incorrectly with the others operation.  This is why
merging is fine.  Since the new method would have to be integrated at
development time into 1 LSM  so there could not be conflits.

Peter Dolding

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [TOMOYO 1/2] tomoyo: add Documentation/tomoyo.txt
  2009-04-08 13:31 ` [TOMOYO 1/2] tomoyo: add Documentation/tomoyo.txt Tetsuo Handa
  2009-04-10 12:26   ` Peter Dolding
@ 2009-04-10 17:10   ` Pavel Machek
  2009-04-13  2:04     ` Tetsuo Handa
  1 sibling, 1 reply; 34+ messages in thread
From: Pavel Machek @ 2009-04-10 17:10 UTC (permalink / raw)
  To: Tetsuo Handa
  Cc: jmorris, linux-security-module, linux-kernel, Kentaro Takeda,
	Toshiharu Harada

On Wed 2009-04-08 22:31:27, Tetsuo Handa wrote:
> Signed-off-by: Kentaro Takeda <takedakn@nttdata.co.jp>
> Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
> Signed-off-by: Toshiharu Harada <haradats@nttdata.co.jp>

Could we get an user<->kernel interface documentation?

> +--- How to enable TOMOYO? ---
> +
> +Build the kernel with CONFIG_SECURITY_TOMOYO=y and pass "security=tomoyo" to
> +kernel's command line.

"on kernel's" ?

> +--- Where are documentations? ---

"Where is documentation?"

									Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [TOMOYO 1/2] tomoyo: add Documentation/tomoyo.txt
  2009-04-10 17:10   ` Pavel Machek
@ 2009-04-13  2:04     ` Tetsuo Handa
  2009-04-29 13:13       ` Pavel Machek
  2009-05-01 10:24       ` Pavel Machek
  0 siblings, 2 replies; 34+ messages in thread
From: Tetsuo Handa @ 2009-04-13  2:04 UTC (permalink / raw)
  To: pavel, jmorris; +Cc: linux-security-module, linux-kernel

Hello.

Pavel Machek wrote:
> Could we get an user<->kernel interface documentation?

It is at http://tomoyo.sourceforge.jp/en/2.2.x/policy-reference.html .

> > +--- How to enable TOMOYO? ---
> > +
> > +Build the kernel with CONFIG_SECURITY_TOMOYO=y and pass "security=tomoyo" to
> > +kernel's command line.
> 
> "on kernel's" ?
> 
> > +--- Where are documentations? ---
> 
> "Where is documentation?"

Updated. Thanks.

James, please apply the below updated one and the one at http://lkml.org/lkml/2009/4/10/170 (Subject: [TOMOYO 2/2] tomoyo: version bump to 2.2.0.).
----------
Subject: tomoyo: add Documentation/tomoyo.txt

Signed-off-by: Kentaro Takeda <takedakn@nttdata.co.jp>
Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Signed-off-by: Toshiharu Harada <haradats@nttdata.co.jp>
---
 Documentation/tomoyo.txt |   55 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 55 insertions(+)

--- /dev/null
+++ linux-2.6.30-rc1/Documentation/tomoyo.txt
@@ -0,0 +1,55 @@
+--- What is TOMOYO? ---
+
+TOMOYO is a name-based MAC extension (LSM module) for the Linux kernel.
+
+LiveCD-based tutorials are available at
+http://tomoyo.sourceforge.jp/en/1.6.x/1st-step/ubuntu8.04-live/
+http://tomoyo.sourceforge.jp/en/1.6.x/1st-step/centos5-live/ .
+Though these tutorials use non-LSM version of TOMOYO, they are useful for you
+to know what TOMOYO is.
+
+--- How to enable TOMOYO? ---
+
+Build the kernel with CONFIG_SECURITY_TOMOYO=y and pass "security=tomoyo" on
+kernel's command line.
+
+Please see http://tomoyo.sourceforge.jp/en/2.2.x/ for details.
+
+--- Where is documentation? ---
+
+User <-> Kernel interface documentation is available at
+http://tomoyo.sourceforge.jp/en/2.2.x/policy-reference.html .
+
+Materials we prepared for seminars and symposiums are available at
+http://sourceforge.jp/projects/tomoyo/docs/?category_id=532&language_id=1 .
+Below lists are chosen from three aspects.
+
+What is TOMOYO?
+  TOMOYO Linux Overview
+    http://sourceforge.jp/projects/tomoyo/docs/lca2009-takeda.pdf
+  TOMOYO Linux: pragmatic and manageable security for Linux
+    http://sourceforge.jp/projects/tomoyo/docs/freedomhectaipei-tomoyo.pdf
+  TOMOYO Linux: A Practical Method to Understand and Protect Your Own Linux Box
+    http://sourceforge.jp/projects/tomoyo/docs/PacSec2007-en-no-demo.pdf
+
+What can TOMOYO do?
+  Deep inside TOMOYO Linux
+    http://sourceforge.jp/projects/tomoyo/docs/lca2009-kumaneko.pdf
+  The role of "pathname based access control" in security.
+    http://sourceforge.jp/projects/tomoyo/docs/lfj2008-bof.pdf
+
+History of TOMOYO?
+  Realities of Mainlining
+    http://sourceforge.jp/projects/tomoyo/docs/lfj2008.pdf
+
+--- What is future plan? ---
+
+We believe that inode based security and name based security are complementary
+and both should be used together. But unfortunately, so far, we cannot enable
+multiple LSM modules at the same time. We feel sorry that you have to give up
+SELinux/SMACK/AppArmor etc. when you want to use TOMOYO.
+
+We hope that LSM becomes stackable in future. Meanwhile, you can use non-LSM
+version of TOMOYO, available at http://tomoyo.sourceforge.jp/en/1.6.x/ .
+LSM version of TOMOYO is a subset of non-LSM version of TOMOYO. We are planning
+to port non-LSM version's functionalities to LSM versions.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [TOMOYO 1/2] tomoyo: add Documentation/tomoyo.txt
  2009-04-13  2:04     ` Tetsuo Handa
@ 2009-04-29 13:13       ` Pavel Machek
  2009-05-01 10:24       ` Pavel Machek
  1 sibling, 0 replies; 34+ messages in thread
From: Pavel Machek @ 2009-04-29 13:13 UTC (permalink / raw)
  To: Tetsuo Handa; +Cc: jmorris, linux-security-module, linux-kernel

On Mon 2009-04-13 11:04:19, Tetsuo Handa wrote:
> Hello.
> 
> Pavel Machek wrote:
> > Could we get an user<->kernel interface documentation?
> 
> It is at http://tomoyo.sourceforge.jp/en/2.2.x/policy-reference.html
.

Ouch:

2.5 Memory Allocation Rules

In TOMOYO Linux, memory allocated for holding access permissions and
words are never freed. There is no way except rebooting the system
that can free unneeded memory.

But don't worry. The policy seldom changes after you start production
mode. By tuning policy before starting production mode, you can reduce
memory usage to (usually) less than 1 MB.

....does that mean that it leaks memory by design?
									Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [TOMOYO 1/2] tomoyo: add Documentation/tomoyo.txt
  2009-04-13  2:04     ` Tetsuo Handa
  2009-04-29 13:13       ` Pavel Machek
@ 2009-05-01 10:24       ` Pavel Machek
  2009-05-01 13:07         ` Tetsuo Handa
  1 sibling, 1 reply; 34+ messages in thread
From: Pavel Machek @ 2009-05-01 10:24 UTC (permalink / raw)
  To: Tetsuo Handa; +Cc: jmorris, linux-security-module, linux-kernel

On Mon 2009-04-13 11:04:19, Tetsuo Handa wrote:
> Hello.
> 
> Pavel Machek wrote:
> > Could we get an user<->kernel interface documentation?
> 
> It is at http://tomoyo.sourceforge.jp/en/2.2.x/policy-reference.html
.

Ouch:

2.5 Memory Allocation Rules

In TOMOYO Linux, memory allocated for holding access permissions and
words are never freed. There is no way except rebooting the system
that can free unneeded memory.

But don't worry. The policy seldom changes after you start production
mode. By tuning policy before starting production mode, you can reduce
memory usage to (usually) less than 1 MB.

....does that mean that it leaks memory by design?
									Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [TOMOYO 1/2] tomoyo: add Documentation/tomoyo.txt
  2009-05-01 10:24       ` Pavel Machek
@ 2009-05-01 13:07         ` Tetsuo Handa
  2009-05-03 21:56           ` Pavel Machek
  0 siblings, 1 reply; 34+ messages in thread
From: Tetsuo Handa @ 2009-05-01 13:07 UTC (permalink / raw)
  To: pavel; +Cc: jmorris, linux-security-module, linux-kernel

Sorry for delayed response.

Pavel Machek wrote:
> 2.5 Memory Allocation Rules
> 
> In TOMOYO Linux, memory allocated for holding access permissions and
> words are never freed. There is no way except rebooting the system
> that can free unneeded memory.
> 
> But don't worry. The policy seldom changes after you start production
> mode. By tuning policy before starting production mode, you can reduce
> memory usage to (usually) less than 1 MB.
> 
> ....does that mean that it leaks memory by design?

This is memory leak, but *controlled* memory allocation with a strategy for
avoiding memory fragmentation and reducing memory usage. kstrdup()ing string
data produces partially unused memory block since string data's length is
unlikely power of two. Therefore, TOMOYO allocates memory in PAGE_SIZE bytes
block and embeds string data as much as possible.
TOMOYO does not continue allocating forever.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [TOMOYO 1/2] tomoyo: add Documentation/tomoyo.txt
  2009-05-01 13:07         ` Tetsuo Handa
@ 2009-05-03 21:56           ` Pavel Machek
  2009-05-04  6:24             ` Tetsuo Handa
  0 siblings, 1 reply; 34+ messages in thread
From: Pavel Machek @ 2009-05-03 21:56 UTC (permalink / raw)
  To: Tetsuo Handa; +Cc: jmorris, linux-security-module, linux-kernel

On Fri 2009-05-01 22:07:31, Tetsuo Handa wrote:
> Sorry for delayed response.
> 
> Pavel Machek wrote:
> > 2.5 Memory Allocation Rules
> > 
> > In TOMOYO Linux, memory allocated for holding access permissions and
> > words are never freed. There is no way except rebooting the system
> > that can free unneeded memory.
> > 
> > But don't worry. The policy seldom changes after you start production
> > mode. By tuning policy before starting production mode, you can reduce
> > memory usage to (usually) less than 1 MB.
> > 
> > ....does that mean that it leaks memory by design?
> 
> This is memory leak, but *controlled* memory allocation with a strategy for
> avoiding memory fragmentation and reducing memory usage. kstrdup()ing string
> data produces partially unused memory block since string data's length is
> unlikely power of two. Therefore, TOMOYO allocates memory in PAGE_SIZE bytes
> block and embeds string data as much as possible.
> TOMOYO does not continue allocating forever.

The document above says otherwise. 'There is no way except rebooting
the system that can free unneeded memory' certainly looks like memory
leak. Plus it sounds like if you change the policy, it will not free
the old one, either.

								Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [TOMOYO 1/2] tomoyo: add Documentation/tomoyo.txt
  2009-05-03 21:56           ` Pavel Machek
@ 2009-05-04  6:24             ` Tetsuo Handa
  2009-05-06 12:16               ` Tetsuo Handa
  0 siblings, 1 reply; 34+ messages in thread
From: Tetsuo Handa @ 2009-05-04  6:24 UTC (permalink / raw)
  To: pavel; +Cc: jmorris, linux-security-module, linux-kernel

Pavel Machek wrote:
> The document above says otherwise. 'There is no way except rebooting
> the system that can free unneeded memory' certainly looks like memory
> leak. Plus it sounds like if you change the policy, it will not free
> the old one, either.

Comments on documentation are also appreciated.
Let me explain it with below examle.

# echo 'allow_read /lib/libc-2.5.so' | ccs-loadpolicy -e
# echo 'delete allow_read /lib/libc-2.5.so' | ccs-loadpolicy -e
# echo 'allow_read /lib/libc-2.5.so' | ccs-loadpolicy -e
# echo 'allow_read /lib/libc-2.6.so' | ccs-loadpolicy -e

In the first line, new memory is allocated because that element has never been
added to the list before.
In the second line, memory used for the deleted element is not released.
In the third line, new memory is not allocated because that element has been
added in the past.
In the fourth line, new memory is allocated because that element has never been
added to the list before.

Memory which becomes garbage (which some people call as "memory leak") is
quite little because a sane administrator won't add random elements and delete
them.

TOMOYO has cursors used for resuming list traversal from arbitrary elements.
I tried to add refcounter to each element, but the code became too ugly to
maintain. Thus, I simplified list traversal by guaranteeing all elements
pointed by cursors are permanent. As of now, we can't release memory used by
the deleted element because we don't manage the list of cursors to make sure
that there is no cursor which refers the deleted element. But if we can find
a way to detect no longer referenced elements, we would be able to add some
garbage collector. (Before we start implementing garbage collector, I'd like to
hear end-user's opinion whether TOMOYO wants garbage collector or not.)

Thanks.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [TOMOYO 1/2] tomoyo: add Documentation/tomoyo.txt
  2009-05-04  6:24             ` Tetsuo Handa
@ 2009-05-06 12:16               ` Tetsuo Handa
  2009-05-07 11:42                 ` [TOMOYO] Add garbage collector support Tetsuo Handa
  2009-05-14 12:08                 ` [PATCH] TOMOYO: Add garbage collector support. (v2) Tetsuo Handa
  0 siblings, 2 replies; 34+ messages in thread
From: Tetsuo Handa @ 2009-05-06 12:16 UTC (permalink / raw)
  To: pavel; +Cc: jmorris, linux-security-module, linux-kernel

Tetsuo Handa wrote:
> TOMOYO has cursors used for resuming list traversal from arbitrary elements.
> I tried to add refcounter to each element, but the code became too ugly to
> maintain. Thus, I simplified list traversal by guaranteeing all elements
> pointed by cursors are permanent. As of now, we can't release memory used by
> the deleted element because we don't manage the list of cursors to make sure
> that there is no cursor which refers the deleted element.

Just for information, I tried to implement some garbage collector.
http://svn.sourceforge.jp/cgi-bin/viewcvs.cgi/trunk/2.2.x/tomoyo-lsm/patches/tomoyo-gc.patch?view=
markup&revision=2506&root=tomoyo
Not checked the patch for details, but I think it is less ugly than
my previous implementation.

Rough estimate is shown below.


(1) Current implementation, booted CentOS 5.3 with learning mode.

Memory: 492736k/524288k available (4730k kernel code, 30668k reserved, 4947k data, 1668k init, 0k 
highmem)

# ccs-savepolicy -u
Shared:      135168
Private:     208896
Dynamic:        704
Total:       344768


(2a) With the patch above, booted CentOS 5.3 with learning mode.

Memory: 492736k/524288k available (4732k kernel code, 30676k reserved, 4953k data, 1668k init, 0k 
highmem)

# ccs-savepolicy -u
Shared:      333280
Private:     200000
Dynamic:        704
Total:       533984

(2b) With the patch above, removed policy as much as possible after (2a).

# ccs-savepolicy -u
Shared:        2400
Private:       1120
Dynamic:        704
Total:         4224


The difference comes from mainly how TOMOYO keeps string data.

Case 1 embeds multiple strings into kmalloc(PAGE_SIZE), but can't kfree().
By not implementing garbage collector, we can save about 200kB of RAM
if an administrator does not delete current policy.

Case 2a and 2b use kstrdup() for each string, and can kfree().
By implementing garbage collector, we can release about 520kB of RAM
if an administrator completely deletes current policy.

Please remember that in case 1, reloading the policy which was loaded in the
past will not consume memory (because it simply clears is_deleted flag instead
of allocating memory).
The amount of memory finally saved depends on how large policy changes occur.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [TOMOYO] Add garbage collector support.
  2009-05-06 12:16               ` Tetsuo Handa
@ 2009-05-07 11:42                 ` Tetsuo Handa
  2009-05-08  1:43                   ` James Morris
  2009-05-08  9:32                   ` Pavel Machek
  2009-05-14 12:08                 ` [PATCH] TOMOYO: Add garbage collector support. (v2) Tetsuo Handa
  1 sibling, 2 replies; 34+ messages in thread
From: Tetsuo Handa @ 2009-05-07 11:42 UTC (permalink / raw)
  To: pavel, jmorris; +Cc: linux-security-module, linux-kernel

A process who is reading/writing list elements has pointers which point to
(possibly marked-as-deleted) list elements and releases a lock when the process
leaves the kernel.

As of now, TOMOYO cannot release memory used by marked-as-deleted list elements
because TOMOYO does not manage list of pointers.

This patch makes TOMOYO to manage list of pointers and allows an administrator
release memory used by marked-as-deleted list elements.

Memory Management Rules:

  When reading list elements, a process takes tomoyo_policy_lock for reading.
  When writing list elements, a process takes tomoyo_policy_lock for writing.

  When a process finished reading list elements, a garbage collector function
  is called after the process released tomoyo_policy_lock.
  The garbage collector function takes tomoyo_policy_lock for writing and
  traverses the lists and releases elements if that element has is_deleted flag
  set.

  Since strings are likely referenced by multiple list elements, this patch
  assigns a refcounter to each string.
  The policy add/del function increments the refcounter only if the element is
  added to the list. The garbage collector function decrements the refcounter
  only if the element is not referred by a process.
  The garbage collector function releases memory of the string if the string's
  refcounter becomes 0.

  "struct tomoyo_io_buffer" remembers pointer to list elements.
  Thus, TOMOYO memorizes the address of "struct tomoyo_io_buffer"->read_var1,
  "struct tomoyo_io_buffer"->read_var2, "struct tomoyo_io_buffer"->write_var1
  when a file in /sys/kernel/security/tomoyo/ interface is opened and forgets
  them when that file is closed.

  "struct task_struct"->cred->security also remembers pointer to list elements.
  Thus, TOMOYO memorizes the address of cred->security at
  security_cred_prepare() and forgets it at security_cred_free().

  tomoyo_update_cookie() is called with tomoyo_policy_lock held for reading
  when the pointer refers a different list element.

  tomoyo_used_by_cookie() is called with tomoyo_policy_lock held for writing
  to check whether the pointer is referenced by a cookie or not.


Now, TOMOYO can release memory. :-)

Attached patch is for security-testing-2.6#next.
James, it is possible to apply below commits to security-testing-2.6#next ?
I get a lot of warning messages in my environment.

39826a1e17c1957bd7b5cd7815b83940e5e3a230 tomoyo: version bump to 2.2.0. 
17a7b7b39056a82c5012539311850f202e6c3cd4 tomoyo: add Documentation/tomoyo.txt
05fa199d45c54a9bda7aa3ae6537253d6f097aa9 mm: pass correct mm when growing stack
05f54c13cd0c33694eec39a265475c5d6cf223cf Revert "kobject: don't block for each kobject_uevent".
a964e33c5d7c0ea46376d20c2f02edf01c9db251 x86: clean up old gcc warnings


Regards.
--------------------
Subject: [TOMOYO] Add garbage collector support.

A process who is reading/writing list elements has pointers which point to
(possibly marked-as-deleted) list elements and releases a lock when the process
leaves the kernel.

As of now, TOMOYO cannot release memory used by marked-as-deleted list elements
because TOMOYO does not manage list of pointers.

This patch makes TOMOYO to manage list of pointers and allows an administrator
release memory used by marked-as-deleted list elements.

Signed-off-by: Kentaro Takeda <takedakn@nttdata.co.jp>
Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Signed-off-by: Toshiharu Harada <haradats@nttdata.co.jp>
---
 security/tomoyo/common.c   |  259 ++++++++++++++++++++++++++++----------------
 security/tomoyo/common.h   |   37 ++++--
 security/tomoyo/domain.c   |  237 ++++++++++++++++++++++++----------------
 security/tomoyo/file.c     |  188 +++++++++++++++++++++++---------
 security/tomoyo/realpath.c |  264 ++++++++++++++++++++++++++-------------------
 security/tomoyo/realpath.h |   43 +++++--
 security/tomoyo/tomoyo.c   |   40 ++++--
 security/tomoyo/tomoyo.h   |   13 --
 8 files changed, 689 insertions(+), 392 deletions(-)

--- security-testing-2.6.git.orig/security/tomoyo/common.c
+++ security-testing-2.6.git/security/tomoyo/common.c
@@ -12,8 +12,8 @@
 #include <linux/uaccess.h>
 #include <linux/security.h>
 #include <linux/hardirq.h>
-#include "realpath.h"
 #include "common.h"
+#include "realpath.h"
 #include "tomoyo.h"
 
 /* Has loading policy done? */
@@ -326,13 +326,13 @@ bool tomoyo_is_domain_def(const unsigned
  * tomoyo_find_domain - Find a domain by the given name.
  *
  * @domainname: The domainname to find.
+ * @cookie:     Pointer to "struct tomoyo_cookie".
  *
- * Caller must call down_read(&tomoyo_domain_list_lock); or
- * down_write(&tomoyo_domain_list_lock); .
+ * Caller must hold tomoyo_policy_lock.
  *
- * Returns pointer to "struct tomoyo_domain_info" if found, NULL otherwise.
+ * Returns true if found, false otherwise.
  */
-struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname)
+bool tomoyo_find_domain(const char *domainname, struct tomoyo_cookie *cookie)
 {
 	struct tomoyo_domain_info *domain;
 	struct tomoyo_path_info name;
@@ -340,11 +340,13 @@ struct tomoyo_domain_info *tomoyo_find_d
 	name.name = domainname;
 	tomoyo_fill_path_info(&name);
 	list_for_each_entry(domain, &tomoyo_domain_list, list) {
-		if (!domain->is_deleted &&
-		    !tomoyo_pathcmp(&name, domain->domainname))
-			return domain;
+		if (domain->is_deleted ||
+		    tomoyo_pathcmp(&name, domain->domainname))
+			continue;
+		tomoyo_update_cookie(cookie, domain);
+		return true;
 	}
-	return NULL;
+	return false;
 }
 
 /**
@@ -784,7 +786,7 @@ bool tomoyo_domain_quota_is_ok(struct to
 
 	if (!domain)
 		return true;
-	down_read(&tomoyo_domain_acl_info_list_lock);
+	down_read(&tomoyo_policy_lock);
 	list_for_each_entry(ptr, &domain->acl_info_list, list) {
 		if (ptr->type & TOMOYO_ACL_DELETED)
 			continue;
@@ -838,7 +840,7 @@ bool tomoyo_domain_quota_is_ok(struct to
 			break;
 		}
 	}
-	up_read(&tomoyo_domain_acl_info_list_lock);
+	up_read(&tomoyo_policy_lock);
 	if (count < tomoyo_check_flags(domain, TOMOYO_MAX_ACCEPT_ENTRY))
 		return true;
 	if (!domain->quota_warned) {
@@ -915,7 +917,10 @@ static int tomoyo_write_profile(struct t
 		return -EINVAL;
 	*cp = '\0';
 	if (!strcmp(data, "COMMENT")) {
+		down_write(&tomoyo_policy_lock);
+		tomoyo_del_name(profile->comment);
 		profile->comment = tomoyo_save_name(cp + 1);
+		up_write(&tomoyo_policy_lock);
 		return 0;
 	}
 	for (i = 0; i < TOMOYO_MAX_CONTROL_INDEX; i++) {
@@ -973,9 +978,13 @@ static int tomoyo_read_profile(struct to
 		if (!profile)
 			continue;
 		if (!type) { /* Print profile' comment tag. */
-			if (!tomoyo_io_printf(head, "%u-COMMENT=%s\n",
-					      index, profile->comment ?
-					      profile->comment->name : ""))
+			bool done;
+			down_read(&tomoyo_policy_lock);
+			done = tomoyo_io_printf(head, "%u-COMMENT=%s\n",
+						index, profile->comment ?
+						profile->comment->name : "");
+			up_read(&tomoyo_policy_lock);
+			if (!done)
 				break;
 			continue;
 		}
@@ -1020,7 +1029,6 @@ struct tomoyo_policy_manager_entry {
 
 /* The list for "struct tomoyo_policy_manager_entry". */
 static LIST_HEAD(tomoyo_policy_manager_list);
-static DECLARE_RWSEM(tomoyo_policy_manager_list_lock);
 
 /**
  * tomoyo_update_manager_entry - Add a manager entry.
@@ -1051,7 +1059,7 @@ static int tomoyo_update_manager_entry(c
 	if (!saved_manager)
 		return -ENOMEM;
 	/***** EXCLUSIVE SECTION START *****/
-	down_write(&tomoyo_policy_manager_list_lock);
+	down_write(&tomoyo_policy_lock);
 	list_for_each_entry(ptr, &tomoyo_policy_manager_list, list) {
 		if (ptr->manager != saved_manager)
 			continue;
@@ -1067,11 +1075,13 @@ static int tomoyo_update_manager_entry(c
 	if (!new_entry)
 		goto out;
 	new_entry->manager = saved_manager;
+	saved_manager = NULL;
 	new_entry->is_domain = is_domain;
 	list_add_tail(&new_entry->list, &tomoyo_policy_manager_list);
 	error = 0;
  out:
-	up_write(&tomoyo_policy_manager_list_lock);
+	tomoyo_del_name(saved_manager);
+	up_write(&tomoyo_policy_lock);
 	/***** EXCLUSIVE SECTION END *****/
 	return error;
 }
@@ -1095,6 +1105,23 @@ static int tomoyo_write_manager_policy(s
 	return tomoyo_update_manager_entry(data, is_delete);
 }
 
+static void tomoyo_cleanup_manager(void)
+{
+	struct tomoyo_policy_manager_entry *ptr;
+	struct tomoyo_policy_manager_entry *tmp;
+	/***** EXCLUSIVE SECTION START *****/
+	down_write(&tomoyo_policy_lock);
+	list_for_each_entry_safe(ptr, tmp, &tomoyo_policy_manager_list, list) {
+		if (!ptr->is_deleted || tomoyo_used_by_cookie(ptr))
+			continue;
+		list_del(&ptr->list);
+		tomoyo_del_name(ptr->manager);
+		tomoyo_free_element(ptr);
+	}
+	up_write(&tomoyo_policy_lock);
+	/***** EXCLUSIVE SECTION END *****/
+}
+
 /**
  * tomoyo_read_manager_policy - Read manager policy.
  *
@@ -1109,8 +1136,8 @@ static int tomoyo_read_manager_policy(st
 
 	if (head->read_eof)
 		return 0;
-	down_read(&tomoyo_policy_manager_list_lock);
-	list_for_each_cookie(pos, head->read_var2,
+	down_read(&tomoyo_policy_lock);
+	list_for_each_cookie(pos, head->read_var2.u.list,
 			     &tomoyo_policy_manager_list) {
 		struct tomoyo_policy_manager_entry *ptr;
 		ptr = list_entry(pos, struct tomoyo_policy_manager_entry,
@@ -1122,8 +1149,10 @@ static int tomoyo_read_manager_policy(st
 			break;
 		}
 	}
-	up_read(&tomoyo_policy_manager_list_lock);
+	up_read(&tomoyo_policy_lock);
 	head->read_eof = done;
+	if (done)
+		tomoyo_cleanup_manager();
 	return 0;
 }
 
@@ -1145,7 +1174,7 @@ static bool tomoyo_is_policy_manager(voi
 		return true;
 	if (!tomoyo_manage_by_non_root && (task->cred->uid || task->cred->euid))
 		return false;
-	down_read(&tomoyo_policy_manager_list_lock);
+	down_read(&tomoyo_policy_lock);
 	list_for_each_entry(ptr, &tomoyo_policy_manager_list, list) {
 		if (!ptr->is_deleted && ptr->is_domain
 		    && !tomoyo_pathcmp(domainname, ptr->manager)) {
@@ -1153,13 +1182,13 @@ static bool tomoyo_is_policy_manager(voi
 			break;
 		}
 	}
-	up_read(&tomoyo_policy_manager_list_lock);
+	up_read(&tomoyo_policy_lock);
 	if (found)
 		return true;
 	exe = tomoyo_get_exe();
 	if (!exe)
 		return false;
-	down_read(&tomoyo_policy_manager_list_lock);
+	down_read(&tomoyo_policy_lock);
 	list_for_each_entry(ptr, &tomoyo_policy_manager_list, list) {
 		if (!ptr->is_deleted && !ptr->is_domain
 		    && !strcmp(exe, ptr->manager->name)) {
@@ -1167,7 +1196,7 @@ static bool tomoyo_is_policy_manager(voi
 			break;
 		}
 	}
-	up_read(&tomoyo_policy_manager_list_lock);
+	up_read(&tomoyo_policy_lock);
 	if (!found) { /* Reduce error messages. */
 		static pid_t last_pid;
 		const pid_t pid = current->pid;
@@ -1194,25 +1223,30 @@ static bool tomoyo_is_select_one(struct 
 {
 	unsigned int pid;
 	struct tomoyo_domain_info *domain = NULL;
+	struct tomoyo_cookie *cookie = &head->write_var1;
 
 	if (sscanf(data, "pid=%u", &pid) == 1) {
 		struct task_struct *p;
+		down_read(&tomoyo_policy_lock);
 		/***** CRITICAL SECTION START *****/
-		read_lock(&tasklist_lock);
+		rcu_read_lock();
 		p = find_task_by_vpid(pid);
 		if (p)
 			domain = tomoyo_real_domain(p);
-		read_unlock(&tasklist_lock);
+		rcu_read_unlock();
 		/***** CRITICAL SECTION END *****/
+		if (domain)
+			tomoyo_update_cookie(cookie, domain);
+		up_read(&tomoyo_policy_lock);
 	} else if (!strncmp(data, "domain=", 7)) {
 		if (tomoyo_is_domain_def(data + 7)) {
-			down_read(&tomoyo_domain_list_lock);
-			domain = tomoyo_find_domain(data + 7);
-			up_read(&tomoyo_domain_list_lock);
+			down_read(&tomoyo_policy_lock);
+			if (tomoyo_find_domain(data + 7, cookie))
+				domain = cookie->u.domain;
+			up_read(&tomoyo_policy_lock);
 		}
 	} else
 		return false;
-	head->write_var1 = domain;
 	/* Accessing read_buf is safe because head->io_sem is held. */
 	if (!head->read_buf)
 		return true; /* Do nothing if open(O_WRONLY). */
@@ -1222,15 +1256,15 @@ static bool tomoyo_is_select_one(struct 
 	head->read_eof = !domain;
 	if (domain) {
 		struct tomoyo_domain_info *d;
-		head->read_var1 = NULL;
-		down_read(&tomoyo_domain_list_lock);
+		head->read_var1.u.domain = NULL;
+		down_read(&tomoyo_policy_lock);
 		list_for_each_entry(d, &tomoyo_domain_list, list) {
 			if (d == domain)
 				break;
-			head->read_var1 = &d->list;
+			head->read_var1.u.list = &d->list;
 		}
-		up_read(&tomoyo_domain_list_lock);
-		head->read_var2 = NULL;
+		up_read(&tomoyo_policy_lock);
+		head->read_var2.u.list = NULL;
 		head->read_bit = 0;
 		head->read_step = 0;
 		if (domain->is_deleted)
@@ -1249,7 +1283,7 @@ static bool tomoyo_is_select_one(struct 
 static int tomoyo_write_domain_policy(struct tomoyo_io_buffer *head)
 {
 	char *data = head->write_buf;
-	struct tomoyo_domain_info *domain = head->write_var1;
+	struct tomoyo_domain_info *domain = head->write_var1.u.domain;
 	bool is_delete = false;
 	bool is_select = false;
 	unsigned int profile;
@@ -1264,16 +1298,16 @@ static int tomoyo_write_domain_policy(st
 	if (!tomoyo_is_policy_manager())
 		return -EPERM;
 	if (tomoyo_is_domain_def(data)) {
-		domain = NULL;
-		if (is_delete)
+		struct tomoyo_cookie *cookie = &head->write_var1;
+		if (is_delete) {
 			tomoyo_delete_domain(data);
-		else if (is_select) {
-			down_read(&tomoyo_domain_list_lock);
-			domain = tomoyo_find_domain(data);
-			up_read(&tomoyo_domain_list_lock);
+			tomoyo_update_cookie(cookie, NULL);
+		} else if (is_select) {
+			down_read(&tomoyo_policy_lock);
+			tomoyo_find_domain(data, cookie);
+			up_read(&tomoyo_policy_lock);
 		} else
-			domain = tomoyo_find_or_assign_new_domain(data, 0);
-		head->write_var1 = domain;
+			tomoyo_find_or_assign_new_domain(data, 0, cookie);
 		return 0;
 	}
 	if (!domain)
@@ -1410,6 +1444,57 @@ static bool tomoyo_print_entry(struct to
 	return false;
 }
 
+static void tomoyo_cleanup_domain_policy(void)
+{
+	struct tomoyo_domain_info *domain;
+	struct tomoyo_domain_info *next_domain;
+	/***** EXCLUSIVE SECTION START *****/
+	down_write(&tomoyo_policy_lock);
+	list_for_each_entry_safe(domain, next_domain, &tomoyo_domain_list,
+				 list) {
+		struct tomoyo_acl_info *acl;
+		struct tomoyo_acl_info *next_acl;
+		const bool can_delete_domain = domain->is_deleted &&
+			!tomoyo_used_by_cookie(domain);
+		if (can_delete_domain) {
+			list_for_each_entry(acl, &domain->acl_info_list, list)
+				acl->type |= TOMOYO_ACL_DELETED;
+		}
+		list_for_each_entry_safe(acl, next_acl, &domain->acl_info_list,
+					 list) {
+			if (!(acl->type & TOMOYO_ACL_DELETED)
+			    || tomoyo_used_by_cookie(acl))
+				continue;
+			list_del(&acl->list);
+			switch (tomoyo_acl_type1(acl)) {
+				struct tomoyo_single_path_acl_record *acl1;
+				struct tomoyo_double_path_acl_record *acl2;
+			case TOMOYO_TYPE_SINGLE_PATH_ACL:
+				acl1 = container_of(acl,
+				    struct tomoyo_single_path_acl_record,
+						    head);
+				tomoyo_del_name(acl1->filename);
+				break;
+			case TOMOYO_TYPE_DOUBLE_PATH_ACL:
+				acl2 = container_of(acl,
+				    struct tomoyo_double_path_acl_record,
+						    head);
+				tomoyo_del_name(acl2->filename1);
+				tomoyo_del_name(acl2->filename2);
+				break;
+			}
+			tomoyo_free_element(acl);
+		}
+		if (can_delete_domain && list_empty(&domain->acl_info_list)) {
+			tomoyo_del_name(domain->domainname);
+			list_del(&domain->list);
+			tomoyo_free_element(domain);
+		}
+	}
+	up_write(&tomoyo_policy_lock);
+	/***** EXCLUSIVE SECTION END *****/
+}
+
 /**
  * tomoyo_read_domain_policy - Read domain policy.
  *
@@ -1427,8 +1512,9 @@ static int tomoyo_read_domain_policy(str
 		return 0;
 	if (head->read_step == 0)
 		head->read_step = 1;
-	down_read(&tomoyo_domain_list_lock);
-	list_for_each_cookie(dpos, head->read_var1, &tomoyo_domain_list) {
+	down_read(&tomoyo_policy_lock);
+	list_for_each_cookie(dpos, head->read_var1.u.list,
+			     &tomoyo_domain_list) {
 		struct tomoyo_domain_info *domain;
 		const char *quota_exceeded = "";
 		const char *transition_failed = "";
@@ -1461,18 +1547,16 @@ acl_loop:
 		if (head->read_step == 3)
 			goto tail_mark;
 		/* Print ACL entries in the domain. */
-		down_read(&tomoyo_domain_acl_info_list_lock);
-		list_for_each_cookie(apos, head->read_var2,
-				      &domain->acl_info_list) {
+		list_for_each_cookie(apos, head->read_var2.u.list,
+				     &domain->acl_info_list) {
 			struct tomoyo_acl_info *ptr
 				= list_entry(apos, struct tomoyo_acl_info,
-					      list);
+					     list);
 			if (!tomoyo_print_entry(head, ptr)) {
 				done = false;
 				break;
 			}
 		}
-		up_read(&tomoyo_domain_acl_info_list_lock);
 		if (!done)
 			break;
 		head->read_step = 3;
@@ -1485,8 +1569,10 @@ tail_mark:
 		if (head->read_single_domain)
 			break;
 	}
-	up_read(&tomoyo_domain_list_lock);
+	up_read(&tomoyo_policy_lock);
 	head->read_eof = done;
+	if (done)
+		tomoyo_cleanup_domain_policy();
 	return 0;
 }
 
@@ -1496,30 +1582,25 @@ tail_mark:
  * @head: Pointer to "struct tomoyo_io_buffer".
  *
  * Returns 0 on success, -EINVAL otherwise.
- *
- * This is equivalent to doing
- *
- *     ( echo "select " $domainname; echo "use_profile " $profile ) |
- *     /usr/lib/ccs/loadpolicy -d
  */
 static int tomoyo_write_domain_profile(struct tomoyo_io_buffer *head)
 {
 	char *data = head->write_buf;
 	char *cp = strchr(data, ' ');
-	struct tomoyo_domain_info *domain;
 	unsigned long profile;
+	struct tomoyo_cookie cookie;
 
 	if (!cp)
 		return -EINVAL;
 	*cp = '\0';
-	down_read(&tomoyo_domain_list_lock);
-	domain = tomoyo_find_domain(cp + 1);
-	up_read(&tomoyo_domain_list_lock);
-	if (strict_strtoul(data, 10, &profile))
+	if (strict_strtoul(data, 10, &profile) ||
+	    profile >= TOMOYO_MAX_PROFILES)
 		return -EINVAL;
-	if (domain && profile < TOMOYO_MAX_PROFILES
-	    && (tomoyo_profile_ptr[profile] || !tomoyo_policy_loaded))
-		domain->profile = (u8) profile;
+	down_read(&tomoyo_policy_lock);
+	if (tomoyo_find_domain(cp + 1, &cookie) &&
+	    (tomoyo_profile_ptr[profile] || !tomoyo_policy_loaded))
+		cookie.u.domain->profile = (u8) profile;
+	up_read(&tomoyo_policy_lock);
 	return 0;
 }
 
@@ -1529,13 +1610,6 @@ static int tomoyo_write_domain_profile(s
  * @head: Pointer to "struct tomoyo_io_buffer".
  *
  * Returns list of profile number and domainname pairs.
- *
- * This is equivalent to doing
- *
- *     grep -A 1 '^<kernel>' /sys/kernel/security/tomoyo/domain_policy |
- *     awk ' { if ( domainname == "" ) { if ( $1 == "<kernel>" )
- *     domainname = $0; } else if ( $1 == "use_profile" ) {
- *     print $2 " " domainname; domainname = ""; } } ; '
  */
 static int tomoyo_read_domain_profile(struct tomoyo_io_buffer *head)
 {
@@ -1544,8 +1618,8 @@ static int tomoyo_read_domain_profile(st
 
 	if (head->read_eof)
 		return 0;
-	down_read(&tomoyo_domain_list_lock);
-	list_for_each_cookie(pos, head->read_var1, &tomoyo_domain_list) {
+	down_read(&tomoyo_policy_lock);
+	list_for_each_cookie(pos, head->read_var1.u.list, &tomoyo_domain_list) {
 		struct tomoyo_domain_info *domain;
 		domain = list_entry(pos, struct tomoyo_domain_info, list);
 		if (domain->is_deleted)
@@ -1556,7 +1630,7 @@ static int tomoyo_read_domain_profile(st
 			break;
 		}
 	}
-	up_read(&tomoyo_domain_list_lock);
+	up_read(&tomoyo_policy_lock);
 	head->read_eof = done;
 	return 0;
 }
@@ -1595,11 +1669,11 @@ static int tomoyo_read_pid(struct tomoyo
 		struct task_struct *p;
 		struct tomoyo_domain_info *domain = NULL;
 		/***** CRITICAL SECTION START *****/
-		read_lock(&tasklist_lock);
+		rcu_read_lock();
 		p = find_task_by_vpid(pid);
 		if (p)
 			domain = tomoyo_real_domain(p);
-		read_unlock(&tasklist_lock);
+		rcu_read_unlock();
 		/***** CRITICAL SECTION END *****/
 		if (domain)
 			tomoyo_io_printf(head, "%d %u %s", pid, domain->profile,
@@ -1655,43 +1729,43 @@ static int tomoyo_read_exception_policy(
 	if (!head->read_eof) {
 		switch (head->read_step) {
 		case 0:
-			head->read_var2 = NULL;
+			head->read_var2.u.list = NULL;
 			head->read_step = 1;
 		case 1:
 			if (!tomoyo_read_domain_keeper_policy(head))
 				break;
-			head->read_var2 = NULL;
+			head->read_var2.u.list = NULL;
 			head->read_step = 2;
 		case 2:
 			if (!tomoyo_read_globally_readable_policy(head))
 				break;
-			head->read_var2 = NULL;
+			head->read_var2.u.list = NULL;
 			head->read_step = 3;
 		case 3:
-			head->read_var2 = NULL;
+			head->read_var2.u.list = NULL;
 			head->read_step = 4;
 		case 4:
 			if (!tomoyo_read_domain_initializer_policy(head))
 				break;
-			head->read_var2 = NULL;
+			head->read_var2.u.list = NULL;
 			head->read_step = 5;
 		case 5:
 			if (!tomoyo_read_alias_policy(head))
 				break;
-			head->read_var2 = NULL;
+			head->read_var2.u.list = NULL;
 			head->read_step = 6;
 		case 6:
-			head->read_var2 = NULL;
+			head->read_var2.u.list = NULL;
 			head->read_step = 7;
 		case 7:
 			if (!tomoyo_read_file_pattern(head))
 				break;
-			head->read_var2 = NULL;
+			head->read_var2.u.list = NULL;
 			head->read_step = 8;
 		case 8:
 			if (!tomoyo_read_no_rewrite_policy(head))
 				break;
-			head->read_var2 = NULL;
+			head->read_var2.u.list = NULL;
 			head->read_step = 9;
 		case 9:
 			head->read_eof = true;
@@ -1778,7 +1852,7 @@ void tomoyo_load_policy(const char *file
 	tomoyo_policy_loaded = true;
 	{ /* Check all profiles currently assigned to domains are defined. */
 		struct tomoyo_domain_info *domain;
-		down_read(&tomoyo_domain_list_lock);
+		down_read(&tomoyo_policy_lock);
 		list_for_each_entry(domain, &tomoyo_domain_list, list) {
 			const u8 profile = domain->profile;
 			if (tomoyo_profile_ptr[profile])
@@ -1786,7 +1860,7 @@ void tomoyo_load_policy(const char *file
 			panic("Profile %u (used by '%s') not defined.\n",
 			      profile, domain->domainname->name);
 		}
-		up_read(&tomoyo_domain_list_lock);
+		up_read(&tomoyo_policy_lock);
 	}
 }
 
@@ -1919,6 +1993,9 @@ static int tomoyo_open_control(const u8 
 			return -ENOMEM;
 		}
 	}
+	tomoyo_add_cookie(&head->read_var1, NULL);
+	tomoyo_add_cookie(&head->read_var2, NULL);
+	tomoyo_add_cookie(&head->write_var1, NULL);
 	file->private_data = head;
 	/*
 	 * Call the handler now if the file is
@@ -2043,6 +2120,9 @@ static int tomoyo_close_control(struct f
 	head->read_buf = NULL;
 	tomoyo_free(head->write_buf);
 	head->write_buf = NULL;
+	tomoyo_del_cookie(&head->read_var1);
+	tomoyo_del_cookie(&head->read_var2);
+	tomoyo_del_cookie(&head->write_var1);
 	tomoyo_free(head);
 	head = NULL;
 	file->private_data = NULL;
@@ -2171,9 +2251,10 @@ static void __init tomoyo_create_entry(c
 static int __init tomoyo_initerface_init(void)
 {
 	struct dentry *tomoyo_dir;
+	struct tomoyo_cookie *cookie = current_cred()->security;
 
 	/* Don't create securityfs entries unless registered. */
-	if (current_cred()->security != &tomoyo_kernel_domain)
+	if (!cookie || cookie->u.domain != &tomoyo_kernel_domain)
 		return 0;
 
 	tomoyo_dir = securityfs_create_dir("tomoyo", NULL);
--- security-testing-2.6.git.orig/security/tomoyo/common.h
+++ security-testing-2.6.git/security/tomoyo/common.h
@@ -26,6 +26,18 @@
 struct dentry;
 struct vfsmount;
 
+struct tomoyo_domain_info;
+struct tomoyo_path_info;
+struct tomoyo_cookie {
+	struct list_head list;
+	union {
+		const void *ptr;
+		struct list_head *list;
+		struct tomoyo_domain_info *domain;
+		const struct tomoyo_path_info *path;
+	} u;
+};
+
 /* Temporary buffer for holding pathnames. */
 struct tomoyo_page_buffer {
 	char buffer[4096];
@@ -160,11 +172,11 @@ struct tomoyo_io_buffer {
 	/* Exclusive lock for this structure.   */
 	struct mutex io_sem;
 	/* The position currently reading from. */
-	struct list_head *read_var1;
+	struct tomoyo_cookie read_var1;
 	/* Extra variables for reading.         */
-	struct list_head *read_var2;
+	struct tomoyo_cookie read_var2;
 	/* The position currently writing to.   */
-	struct tomoyo_domain_info *write_var1;
+	struct tomoyo_cookie write_var1;
 	/* The step for reading.                */
 	int read_step;
 	/* Buffer for reading.                  */
@@ -258,11 +270,10 @@ int tomoyo_write_no_rewrite_policy(char 
 /* Create "file_pattern" entry in exception policy. */
 int tomoyo_write_pattern_policy(char *data, const bool is_delete);
 /* Find a domain by the given name. */
-struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname);
+bool tomoyo_find_domain(const char *domainname, struct tomoyo_cookie *cookie);
 /* Find or create a domain by the given name. */
-struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
-							    domainname,
-							    const u8 profile);
+bool tomoyo_find_or_assign_new_domain(const char *domainname, const u8 profile,
+				      struct tomoyo_cookie *cookie);
 /* Check mode for specified functionality. */
 unsigned int tomoyo_check_flags(const struct tomoyo_domain_info *domain,
 				const u8 index);
@@ -276,6 +287,11 @@ void tomoyo_load_policy(const char *file
 void tomoyo_set_domain_flag(struct tomoyo_domain_info *domain,
 			    const bool is_delete, const u8 flags);
 
+static inline struct tomoyo_domain_info *tomoyo_domain(void)
+{
+	return ((struct tomoyo_cookie *) current_cred()->security)->u.domain;
+}
+
 /* strcmp() for "struct tomoyo_path_info" structure. */
 static inline bool tomoyo_pathcmp(const struct tomoyo_path_info *a,
 				  const struct tomoyo_path_info *b)
@@ -319,12 +335,11 @@ static inline bool tomoyo_is_invalid(con
 	return c && (c <= ' ' || c >= 127);
 }
 
+/* Lock for modifying policy. */
+extern struct rw_semaphore tomoyo_policy_lock;
+
 /* The list for "struct tomoyo_domain_info". */
 extern struct list_head tomoyo_domain_list;
-extern struct rw_semaphore tomoyo_domain_list_lock;
-
-/* Lock for domain->acl_info_list. */
-extern struct rw_semaphore tomoyo_domain_acl_info_list_lock;
 
 /* Has /sbin/init started? */
 extern bool tomoyo_policy_loaded;
--- security-testing-2.6.git.orig/security/tomoyo/domain.c
+++ security-testing-2.6.git/security/tomoyo/domain.c
@@ -21,7 +21,7 @@ struct tomoyo_domain_info tomoyo_kernel_
 
 /* The list for "struct tomoyo_domain_info". */
 LIST_HEAD(tomoyo_domain_list);
-DECLARE_RWSEM(tomoyo_domain_list_lock);
+DECLARE_RWSEM(tomoyo_policy_lock);
 
 /* Structure for "initialize_domain" and "no_initialize_domain" keyword. */
 struct tomoyo_domain_initializer_entry {
@@ -96,7 +96,6 @@ const char *tomoyo_get_last_name(const s
 
 /* The list for "struct tomoyo_domain_initializer_entry". */
 static LIST_HEAD(tomoyo_domain_initializer_list);
-static DECLARE_RWSEM(tomoyo_domain_initializer_list_lock);
 
 /**
  * tomoyo_update_domain_initializer_entry - Update "struct tomoyo_domain_initializer_entry" list.
@@ -133,10 +132,12 @@ static int tomoyo_update_domain_initiali
 			return -ENOMEM;
 	}
 	saved_program = tomoyo_save_name(program);
-	if (!saved_program)
+	if (!saved_program) {
+		tomoyo_del_name(saved_domainname);
 		return -ENOMEM;
+	}
 	/***** EXCLUSIVE SECTION START *****/
-	down_write(&tomoyo_domain_initializer_list_lock);
+	down_write(&tomoyo_policy_lock);
 	list_for_each_entry(ptr, &tomoyo_domain_initializer_list, list) {
 		if (ptr->is_not != is_not ||
 		    ptr->domainname != saved_domainname ||
@@ -154,17 +155,40 @@ static int tomoyo_update_domain_initiali
 	if (!new_entry)
 		goto out;
 	new_entry->domainname = saved_domainname;
+	saved_domainname = NULL;
 	new_entry->program = saved_program;
+	saved_program = NULL;
 	new_entry->is_not = is_not;
 	new_entry->is_last_name = is_last_name;
 	list_add_tail(&new_entry->list, &tomoyo_domain_initializer_list);
 	error = 0;
  out:
-	up_write(&tomoyo_domain_initializer_list_lock);
+	tomoyo_del_name(saved_domainname);
+	tomoyo_del_name(saved_program);
+	up_write(&tomoyo_policy_lock);
 	/***** EXCLUSIVE SECTION END *****/
 	return error;
 }
 
+static void tomoyo_cleanup_initializer(void)
+{
+	struct tomoyo_domain_initializer_entry *ptr;
+	struct tomoyo_domain_initializer_entry *tmp;
+	/***** EXCLUSIVE SECTION START *****/
+	down_write(&tomoyo_policy_lock);
+	list_for_each_entry_safe(ptr, tmp, &tomoyo_domain_initializer_list,
+				 list) {
+		if (!ptr->is_deleted || tomoyo_used_by_cookie(ptr))
+			continue;
+		list_del(&ptr->list);
+		tomoyo_del_name(ptr->domainname);
+		tomoyo_del_name(ptr->program);
+		tomoyo_free_element(ptr);
+	}
+	up_write(&tomoyo_policy_lock);
+	/***** EXCLUSIVE SECTION END *****/
+}
+
 /**
  * tomoyo_read_domain_initializer_policy - Read "struct tomoyo_domain_initializer_entry" list.
  *
@@ -177,8 +201,8 @@ bool tomoyo_read_domain_initializer_poli
 	struct list_head *pos;
 	bool done = true;
 
-	down_read(&tomoyo_domain_initializer_list_lock);
-	list_for_each_cookie(pos, head->read_var2,
+	down_read(&tomoyo_policy_lock);
+	list_for_each_cookie(pos, head->read_var2.u.list,
 			     &tomoyo_domain_initializer_list) {
 		const char *no;
 		const char *from = "";
@@ -201,7 +225,9 @@ bool tomoyo_read_domain_initializer_poli
 			break;
 		}
 	}
-	up_read(&tomoyo_domain_initializer_list_lock);
+	up_read(&tomoyo_policy_lock);
+	if (done)
+		tomoyo_cleanup_initializer();
 	return done;
 }
 
@@ -248,7 +274,7 @@ static bool tomoyo_is_domain_initializer
 	struct tomoyo_domain_initializer_entry *ptr;
 	bool flag = false;
 
-	down_read(&tomoyo_domain_initializer_list_lock);
+	down_read(&tomoyo_policy_lock);
 	list_for_each_entry(ptr,  &tomoyo_domain_initializer_list, list) {
 		if (ptr->is_deleted)
 			continue;
@@ -269,13 +295,12 @@ static bool tomoyo_is_domain_initializer
 		}
 		flag = true;
 	}
-	up_read(&tomoyo_domain_initializer_list_lock);
+	up_read(&tomoyo_policy_lock);
 	return flag;
 }
 
 /* The list for "struct tomoyo_domain_keeper_entry". */
 static LIST_HEAD(tomoyo_domain_keeper_list);
-static DECLARE_RWSEM(tomoyo_domain_keeper_list_lock);
 
 /**
  * tomoyo_update_domain_keeper_entry - Update "struct tomoyo_domain_keeper_entry" list.
@@ -313,10 +338,12 @@ static int tomoyo_update_domain_keeper_e
 			return -ENOMEM;
 	}
 	saved_domainname = tomoyo_save_name(domainname);
-	if (!saved_domainname)
+	if (!saved_domainname) {
+		tomoyo_del_name(saved_program);
 		return -ENOMEM;
+	}
 	/***** EXCLUSIVE SECTION START *****/
-	down_write(&tomoyo_domain_keeper_list_lock);
+	down_write(&tomoyo_policy_lock);
 	list_for_each_entry(ptr, &tomoyo_domain_keeper_list, list) {
 		if (ptr->is_not != is_not ||
 		    ptr->domainname != saved_domainname ||
@@ -334,13 +361,17 @@ static int tomoyo_update_domain_keeper_e
 	if (!new_entry)
 		goto out;
 	new_entry->domainname = saved_domainname;
+	saved_domainname = NULL;
 	new_entry->program = saved_program;
+	saved_program = NULL;
 	new_entry->is_not = is_not;
 	new_entry->is_last_name = is_last_name;
 	list_add_tail(&new_entry->list, &tomoyo_domain_keeper_list);
 	error = 0;
  out:
-	up_write(&tomoyo_domain_keeper_list_lock);
+	tomoyo_del_name(saved_domainname);
+	tomoyo_del_name(saved_program);
+	up_write(&tomoyo_policy_lock);
 	/***** EXCLUSIVE SECTION END *****/
 	return error;
 }
@@ -366,6 +397,24 @@ int tomoyo_write_domain_keeper_policy(ch
 	return tomoyo_update_domain_keeper_entry(data, NULL, is_not, is_delete);
 }
 
+static void tomoyo_cleanup_keep_domain(void)
+{
+	struct tomoyo_domain_keeper_entry *ptr;
+	struct tomoyo_domain_keeper_entry *tmp;
+	/***** EXCLUSIVE SECTION START *****/
+	down_write(&tomoyo_policy_lock);
+	list_for_each_entry_safe(ptr, tmp, &tomoyo_domain_keeper_list, list) {
+		if (!ptr->is_deleted || tomoyo_used_by_cookie(ptr))
+			continue;
+		list_del(&ptr->list);
+		tomoyo_del_name(ptr->domainname);
+		tomoyo_del_name(ptr->program);
+		tomoyo_free_element(ptr);
+	}
+	up_write(&tomoyo_policy_lock);
+	/***** EXCLUSIVE SECTION END *****/
+}
+
 /**
  * tomoyo_read_domain_keeper_policy - Read "struct tomoyo_domain_keeper_entry" list.
  *
@@ -378,8 +427,8 @@ bool tomoyo_read_domain_keeper_policy(st
 	struct list_head *pos;
 	bool done = true;
 
-	down_read(&tomoyo_domain_keeper_list_lock);
-	list_for_each_cookie(pos, head->read_var2,
+	down_read(&tomoyo_policy_lock);
+	list_for_each_cookie(pos, head->read_var2.u.list,
 			     &tomoyo_domain_keeper_list) {
 		struct tomoyo_domain_keeper_entry *ptr;
 		const char *no;
@@ -402,7 +451,9 @@ bool tomoyo_read_domain_keeper_policy(st
 			break;
 		}
 	}
-	up_read(&tomoyo_domain_keeper_list_lock);
+	up_read(&tomoyo_policy_lock);
+	if (done)
+		tomoyo_cleanup_keep_domain();
 	return done;
 }
 
@@ -423,7 +474,7 @@ static bool tomoyo_is_domain_keeper(cons
 	struct tomoyo_domain_keeper_entry *ptr;
 	bool flag = false;
 
-	down_read(&tomoyo_domain_keeper_list_lock);
+	down_read(&tomoyo_policy_lock);
 	list_for_each_entry(ptr, &tomoyo_domain_keeper_list, list) {
 		if (ptr->is_deleted)
 			continue;
@@ -442,13 +493,12 @@ static bool tomoyo_is_domain_keeper(cons
 		}
 		flag = true;
 	}
-	up_read(&tomoyo_domain_keeper_list_lock);
+	up_read(&tomoyo_policy_lock);
 	return flag;
 }
 
 /* The list for "struct tomoyo_alias_entry". */
 static LIST_HEAD(tomoyo_alias_list);
-static DECLARE_RWSEM(tomoyo_alias_list_lock);
 
 /**
  * tomoyo_update_alias_entry - Update "struct tomoyo_alias_entry" list.
@@ -474,10 +524,13 @@ static int tomoyo_update_alias_entry(con
 		return -EINVAL; /* No patterns allowed. */
 	saved_original_name = tomoyo_save_name(original_name);
 	saved_aliased_name = tomoyo_save_name(aliased_name);
-	if (!saved_original_name || !saved_aliased_name)
+	if (!saved_original_name || !saved_aliased_name) {
+		tomoyo_del_name(saved_original_name);
+		tomoyo_del_name(saved_aliased_name);
 		return -ENOMEM;
+	}
 	/***** EXCLUSIVE SECTION START *****/
-	down_write(&tomoyo_alias_list_lock);
+	down_write(&tomoyo_policy_lock);
 	list_for_each_entry(ptr, &tomoyo_alias_list, list) {
 		if (ptr->original_name != saved_original_name ||
 		    ptr->aliased_name != saved_aliased_name)
@@ -494,15 +547,37 @@ static int tomoyo_update_alias_entry(con
 	if (!new_entry)
 		goto out;
 	new_entry->original_name = saved_original_name;
+	saved_original_name = NULL;
 	new_entry->aliased_name = saved_aliased_name;
+	saved_aliased_name = NULL;
 	list_add_tail(&new_entry->list, &tomoyo_alias_list);
 	error = 0;
  out:
-	up_write(&tomoyo_alias_list_lock);
+	tomoyo_del_name(saved_original_name);
+	tomoyo_del_name(saved_aliased_name);
+	up_write(&tomoyo_policy_lock);
 	/***** EXCLUSIVE SECTION END *****/
 	return error;
 }
 
+static void tomoyo_cleanup_alias(void)
+{
+	struct tomoyo_alias_entry *ptr;
+	struct tomoyo_alias_entry *tmp;
+	/***** EXCLUSIVE SECTION START *****/
+	down_write(&tomoyo_policy_lock);
+	list_for_each_entry_safe(ptr, tmp, &tomoyo_alias_list, list) {
+		if (!ptr->is_deleted || tomoyo_used_by_cookie(ptr))
+			continue;
+		list_del(&ptr->list);
+		tomoyo_del_name(ptr->original_name);
+		tomoyo_del_name(ptr->aliased_name);
+		tomoyo_free_element(ptr);
+	}
+	up_write(&tomoyo_policy_lock);
+	/***** EXCLUSIVE SECTION END *****/
+}
+
 /**
  * tomoyo_read_alias_policy - Read "struct tomoyo_alias_entry" list.
  *
@@ -515,8 +590,8 @@ bool tomoyo_read_alias_policy(struct tom
 	struct list_head *pos;
 	bool done = true;
 
-	down_read(&tomoyo_alias_list_lock);
-	list_for_each_cookie(pos, head->read_var2, &tomoyo_alias_list) {
+	down_read(&tomoyo_policy_lock);
+	list_for_each_cookie(pos, head->read_var2.u.list, &tomoyo_alias_list) {
 		struct tomoyo_alias_entry *ptr;
 
 		ptr = list_entry(pos, struct tomoyo_alias_entry, list);
@@ -529,7 +604,9 @@ bool tomoyo_read_alias_policy(struct tom
 			break;
 		}
 	}
-	up_read(&tomoyo_alias_list_lock);
+	up_read(&tomoyo_policy_lock);
+	if (done)
+		tomoyo_cleanup_alias();
 	return done;
 }
 
@@ -568,7 +645,7 @@ int tomoyo_delete_domain(char *domainnam
 	name.name = domainname;
 	tomoyo_fill_path_info(&name);
 	/***** EXCLUSIVE SECTION START *****/
-	down_write(&tomoyo_domain_list_lock);
+	down_write(&tomoyo_policy_lock);
 	/* Is there an active domain? */
 	list_for_each_entry(domain, &tomoyo_domain_list, list) {
 		/* Never delete tomoyo_kernel_domain */
@@ -580,7 +657,7 @@ int tomoyo_delete_domain(char *domainnam
 		domain->is_deleted = true;
 		break;
 	}
-	up_write(&tomoyo_domain_list_lock);
+	up_write(&tomoyo_policy_lock);
 	/***** EXCLUSIVE SECTION END *****/
 	return 0;
 }
@@ -590,81 +667,49 @@ int tomoyo_delete_domain(char *domainnam
  *
  * @domainname: The name of domain.
  * @profile:    Profile number to assign if the domain was newly created.
+ * @cookie:     Pointer to "struct tomoyo_cookie".
  *
- * Returns pointer to "struct tomoyo_domain_info" on success, NULL otherwise.
+ * Returns true on success, false otherwise.
  */
-struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
-							    domainname,
-							    const u8 profile)
+bool tomoyo_find_or_assign_new_domain(const char *domainname, const u8 profile,
+				      struct tomoyo_cookie *cookie)
 {
-	struct tomoyo_domain_info *domain = NULL;
-	const struct tomoyo_path_info *saved_domainname;
+	struct tomoyo_domain_info *domain;
+	const struct tomoyo_path_info *saved_domainname = NULL;
 
 	/***** EXCLUSIVE SECTION START *****/
-	down_write(&tomoyo_domain_list_lock);
-	domain = tomoyo_find_domain(domainname);
-	if (domain)
+	down_write(&tomoyo_policy_lock);
+	if (tomoyo_find_domain(domainname, cookie))
 		goto out;
 	if (!tomoyo_is_correct_domain(domainname, __func__))
 		goto out;
 	saved_domainname = tomoyo_save_name(domainname);
 	if (!saved_domainname)
 		goto out;
-	/* Can I reuse memory of deleted domain? */
-	list_for_each_entry(domain, &tomoyo_domain_list, list) {
-		struct task_struct *p;
-		struct tomoyo_acl_info *ptr;
-		bool flag;
-		if (!domain->is_deleted ||
-		    domain->domainname != saved_domainname)
-			continue;
-		flag = false;
-		/***** CRITICAL SECTION START *****/
-		read_lock(&tasklist_lock);
-		for_each_process(p) {
-			if (tomoyo_real_domain(p) != domain)
-				continue;
-			flag = true;
-			break;
-		}
-		read_unlock(&tasklist_lock);
-		/***** CRITICAL SECTION END *****/
-		if (flag)
-			continue;
-		list_for_each_entry(ptr, &domain->acl_info_list, list) {
-			ptr->type |= TOMOYO_ACL_DELETED;
-		}
-		tomoyo_set_domain_flag(domain, true, domain->flags);
-		domain->profile = profile;
-		domain->quota_warned = false;
-		mb(); /* Avoid out-of-order execution. */
-		domain->is_deleted = false;
-		goto out;
-	}
-	/* No memory reusable. Create using new memory. */
 	domain = tomoyo_alloc_element(sizeof(*domain));
 	if (domain) {
 		INIT_LIST_HEAD(&domain->acl_info_list);
 		domain->domainname = saved_domainname;
+		saved_domainname = NULL;
 		domain->profile = profile;
 		list_add_tail(&domain->list, &tomoyo_domain_list);
+		tomoyo_update_cookie(cookie, domain);
 	}
  out:
-	up_write(&tomoyo_domain_list_lock);
+	tomoyo_del_name(saved_domainname);
+	up_write(&tomoyo_policy_lock);
 	/***** EXCLUSIVE SECTION END *****/
-	return domain;
+	return cookie->u.domain != NULL;
 }
 
 /**
  * tomoyo_find_next_domain - Find a domain.
  *
- * @bprm:           Pointer to "struct linux_binprm".
- * @next_domain:    Pointer to pointer to "struct tomoyo_domain_info".
+ * @bprm: Pointer to "struct linux_binprm".
  *
  * Returns 0 on success, negative value otherwise.
  */
-int tomoyo_find_next_domain(struct linux_binprm *bprm,
-			    struct tomoyo_domain_info **next_domain)
+int tomoyo_find_next_domain(struct linux_binprm *bprm)
 {
 	/*
 	 * This function assumes that the size of buffer returned by
@@ -672,7 +717,6 @@ int tomoyo_find_next_domain(struct linux
 	 */
 	struct tomoyo_page_buffer *tmp = tomoyo_alloc(sizeof(*tmp));
 	struct tomoyo_domain_info *old_domain = tomoyo_domain();
-	struct tomoyo_domain_info *domain = NULL;
 	const char *old_domain_name = old_domain->domainname->name;
 	const char *original_name = bprm->filename;
 	char *new_domain_name = NULL;
@@ -685,6 +729,8 @@ int tomoyo_find_next_domain(struct linux
 	struct tomoyo_path_info s; /* symlink name */
 	struct tomoyo_path_info l; /* last name */
 	static bool initialized;
+	struct tomoyo_cookie *cookie = bprm->cred->security;
+	bool found = false;
 
 	if (!tmp)
 		goto out;
@@ -723,7 +769,7 @@ int tomoyo_find_next_domain(struct linux
 	if (tomoyo_pathcmp(&r, &s)) {
 		struct tomoyo_alias_entry *ptr;
 		/* Is this program allowed to be called via symbolic links? */
-		down_read(&tomoyo_alias_list_lock);
+		down_read(&tomoyo_policy_lock);
 		list_for_each_entry(ptr, &tomoyo_alias_list, list) {
 			if (ptr->is_deleted ||
 			    tomoyo_pathcmp(&r, ptr->original_name) ||
@@ -735,7 +781,7 @@ int tomoyo_find_next_domain(struct linux
 			tomoyo_fill_path_info(&r);
 			break;
 		}
-		up_read(&tomoyo_alias_list_lock);
+		up_read(&tomoyo_policy_lock);
 	}
 
 	/* Check execute permission. */
@@ -755,28 +801,36 @@ int tomoyo_find_next_domain(struct linux
 		 * /sbin/init. But transit from kernel domain if executing
 		 * initializers because they might start before /sbin/init.
 		 */
-		domain = old_domain;
+		found = true;
+		/*
+		 * Since old_domain is already in cookie list,
+		 * tomoyo_policy_lock is not needed.
+		 */
+		tomoyo_update_cookie(cookie, old_domain);
 	} else if (tomoyo_is_domain_keeper(old_domain->domainname, &r, &l)) {
 		/* Keep current domain. */
-		domain = old_domain;
+		found = true;
+		/*
+		 * Since old_domain is already in cookie,
+		 * tomoyo_policy_lock is not needed.
+		 */
+		tomoyo_update_cookie(cookie, old_domain);
 	} else {
 		/* Normal domain transition. */
 		snprintf(new_domain_name, TOMOYO_MAX_PATHNAME_LEN + 1,
 			 "%s %s", old_domain_name, real_program_name);
 	}
-	if (domain || strlen(new_domain_name) >= TOMOYO_MAX_PATHNAME_LEN)
-		goto done;
-	down_read(&tomoyo_domain_list_lock);
-	domain = tomoyo_find_domain(new_domain_name);
-	up_read(&tomoyo_domain_list_lock);
-	if (domain)
-		goto done;
-	if (is_enforce)
+	if (found || strlen(new_domain_name) >= TOMOYO_MAX_PATHNAME_LEN)
 		goto done;
-	domain = tomoyo_find_or_assign_new_domain(new_domain_name,
-						  old_domain->profile);
+	down_read(&tomoyo_policy_lock);
+	found = tomoyo_find_domain(new_domain_name, cookie);
+	up_read(&tomoyo_policy_lock);
+	if (!found && !is_enforce)
+		found = tomoyo_find_or_assign_new_domain(new_domain_name,
+							 old_domain->profile,
+							 cookie);
  done:
-	if (domain)
+	if (found)
 		goto out;
 	printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n",
 	       new_domain_name);
@@ -788,7 +842,6 @@ int tomoyo_find_next_domain(struct linux
  out:
 	tomoyo_free(real_program_name);
 	tomoyo_free(symlink_program_name);
-	*next_domain = domain ? domain : old_domain;
 	tomoyo_free(tmp);
 	return retval;
 }
--- security-testing-2.6.git.orig/security/tomoyo/file.c
+++ security-testing-2.6.git/security/tomoyo/file.c
@@ -130,9 +130,6 @@ static struct tomoyo_path_info *tomoyo_g
 	return NULL;
 }
 
-/* Lock for domain->acl_info_list. */
-DECLARE_RWSEM(tomoyo_domain_acl_info_list_lock);
-
 static int tomoyo_update_double_path_acl(const u8 type, const char *filename1,
 					 const char *filename2,
 					 struct tomoyo_domain_info *
@@ -143,7 +140,6 @@ static int tomoyo_update_single_path_acl
 
 /* The list for "struct tomoyo_globally_readable_file_entry". */
 static LIST_HEAD(tomoyo_globally_readable_list);
-static DECLARE_RWSEM(tomoyo_globally_readable_list_lock);
 
 /**
  * tomoyo_update_globally_readable_entry - Update "struct tomoyo_globally_readable_file_entry" list.
@@ -167,7 +163,7 @@ static int tomoyo_update_globally_readab
 	if (!saved_filename)
 		return -ENOMEM;
 	/***** EXCLUSIVE SECTION START *****/
-	down_write(&tomoyo_globally_readable_list_lock);
+	down_write(&tomoyo_policy_lock);
 	list_for_each_entry(ptr, &tomoyo_globally_readable_list, list) {
 		if (ptr->filename != saved_filename)
 			continue;
@@ -183,10 +179,12 @@ static int tomoyo_update_globally_readab
 	if (!new_entry)
 		goto out;
 	new_entry->filename = saved_filename;
+	saved_filename = NULL;
 	list_add_tail(&new_entry->list, &tomoyo_globally_readable_list);
 	error = 0;
  out:
-	up_write(&tomoyo_globally_readable_list_lock);
+	tomoyo_del_name(saved_filename);
+	up_write(&tomoyo_policy_lock);
 	/***** EXCLUSIVE SECTION END *****/
 	return error;
 }
@@ -203,7 +201,7 @@ static bool tomoyo_is_globally_readable_
 {
 	struct tomoyo_globally_readable_file_entry *ptr;
 	bool found = false;
-	down_read(&tomoyo_globally_readable_list_lock);
+	down_read(&tomoyo_policy_lock);
 	list_for_each_entry(ptr, &tomoyo_globally_readable_list, list) {
 		if (!ptr->is_deleted &&
 		    tomoyo_path_matches_pattern(filename, ptr->filename)) {
@@ -211,7 +209,7 @@ static bool tomoyo_is_globally_readable_
 			break;
 		}
 	}
-	up_read(&tomoyo_globally_readable_list_lock);
+	up_read(&tomoyo_policy_lock);
 	return found;
 }
 
@@ -228,6 +226,24 @@ int tomoyo_write_globally_readable_polic
 	return tomoyo_update_globally_readable_entry(data, is_delete);
 }
 
+static void tomoyo_cleanup_allow_read(void)
+{
+	struct tomoyo_globally_readable_file_entry *ptr;
+	struct tomoyo_globally_readable_file_entry *tmp;
+	/***** EXCLUSIVE SECTION START *****/
+	down_write(&tomoyo_policy_lock);
+	list_for_each_entry_safe(ptr, tmp, &tomoyo_globally_readable_list,
+				 list) {
+		if (!ptr->is_deleted || tomoyo_used_by_cookie(ptr))
+			continue;
+		list_del(&ptr->list);
+		tomoyo_del_name(ptr->filename);
+		tomoyo_free_element(ptr);
+	}
+	up_write(&tomoyo_policy_lock);
+	/***** EXCLUSIVE SECTION END *****/
+}
+
 /**
  * tomoyo_read_globally_readable_policy - Read "struct tomoyo_globally_readable_file_entry" list.
  *
@@ -240,8 +256,8 @@ bool tomoyo_read_globally_readable_polic
 	struct list_head *pos;
 	bool done = true;
 
-	down_read(&tomoyo_globally_readable_list_lock);
-	list_for_each_cookie(pos, head->read_var2,
+	down_read(&tomoyo_policy_lock);
+	list_for_each_cookie(pos, head->read_var2.u.list,
 			     &tomoyo_globally_readable_list) {
 		struct tomoyo_globally_readable_file_entry *ptr;
 		ptr = list_entry(pos,
@@ -255,13 +271,14 @@ bool tomoyo_read_globally_readable_polic
 			break;
 		}
 	}
-	up_read(&tomoyo_globally_readable_list_lock);
+	up_read(&tomoyo_policy_lock);
+	if (done)
+		tomoyo_cleanup_allow_read();
 	return done;
 }
 
 /* The list for "struct tomoyo_pattern_entry". */
 static LIST_HEAD(tomoyo_pattern_list);
-static DECLARE_RWSEM(tomoyo_pattern_list_lock);
 
 /**
  * tomoyo_update_file_pattern_entry - Update "struct tomoyo_pattern_entry" list.
@@ -285,7 +302,7 @@ static int tomoyo_update_file_pattern_en
 	if (!saved_pattern)
 		return -ENOMEM;
 	/***** EXCLUSIVE SECTION START *****/
-	down_write(&tomoyo_pattern_list_lock);
+	down_write(&tomoyo_policy_lock);
 	list_for_each_entry(ptr, &tomoyo_pattern_list, list) {
 		if (saved_pattern != ptr->pattern)
 			continue;
@@ -301,10 +318,12 @@ static int tomoyo_update_file_pattern_en
 	if (!new_entry)
 		goto out;
 	new_entry->pattern = saved_pattern;
+	saved_pattern = NULL;
 	list_add_tail(&new_entry->list, &tomoyo_pattern_list);
 	error = 0;
  out:
-	up_write(&tomoyo_pattern_list_lock);
+	tomoyo_del_name(saved_pattern);
+	up_write(&tomoyo_policy_lock);
 	/***** EXCLUSIVE SECTION END *****/
 	return error;
 }
@@ -312,17 +331,15 @@ static int tomoyo_update_file_pattern_en
 /**
  * tomoyo_get_file_pattern - Get patterned pathname.
  *
- * @filename: The filename to find patterned pathname.
- *
- * Returns pointer to pathname pattern if matched, @filename otherwise.
+ * @cookie: Pointer to "struct tomoyo_cookie".
  */
-static const struct tomoyo_path_info *
-tomoyo_get_file_pattern(const struct tomoyo_path_info *filename)
+static void tomoyo_get_file_pattern(struct tomoyo_cookie *cookie)
 {
 	struct tomoyo_pattern_entry *ptr;
 	const struct tomoyo_path_info *pattern = NULL;
+	const struct tomoyo_path_info *filename = cookie->u.path;
 
-	down_read(&tomoyo_pattern_list_lock);
+	down_read(&tomoyo_policy_lock);
 	list_for_each_entry(ptr, &tomoyo_pattern_list, list) {
 		if (ptr->is_deleted)
 			continue;
@@ -336,10 +353,9 @@ tomoyo_get_file_pattern(const struct tom
 			break;
 		}
 	}
-	up_read(&tomoyo_pattern_list_lock);
 	if (pattern)
-		filename = pattern;
-	return filename;
+		tomoyo_update_cookie(cookie, pattern);
+	up_read(&tomoyo_policy_lock);
 }
 
 /**
@@ -355,6 +371,23 @@ int tomoyo_write_pattern_policy(char *da
 	return tomoyo_update_file_pattern_entry(data, is_delete);
 }
 
+static void tomoyo_cleanup_file_pattern(void)
+{
+	struct tomoyo_pattern_entry *ptr;
+	struct tomoyo_pattern_entry *tmp;
+	/***** EXCLUSIVE SECTION START *****/
+	down_write(&tomoyo_policy_lock);
+	list_for_each_entry_safe(ptr, tmp, &tomoyo_pattern_list, list) {
+		if (!ptr->is_deleted || tomoyo_used_by_cookie(ptr))
+			continue;
+		list_del(&ptr->list);
+		tomoyo_del_name(ptr->pattern);
+		tomoyo_free_element(ptr);
+	}
+	up_write(&tomoyo_policy_lock);
+	/***** EXCLUSIVE SECTION END *****/
+}
+
 /**
  * tomoyo_read_file_pattern - Read "struct tomoyo_pattern_entry" list.
  *
@@ -367,8 +400,9 @@ bool tomoyo_read_file_pattern(struct tom
 	struct list_head *pos;
 	bool done = true;
 
-	down_read(&tomoyo_pattern_list_lock);
-	list_for_each_cookie(pos, head->read_var2, &tomoyo_pattern_list) {
+	down_read(&tomoyo_policy_lock);
+	list_for_each_cookie(pos, head->read_var2.u.list,
+			     &tomoyo_pattern_list) {
 		struct tomoyo_pattern_entry *ptr;
 		ptr = list_entry(pos, struct tomoyo_pattern_entry, list);
 		if (ptr->is_deleted)
@@ -379,13 +413,14 @@ bool tomoyo_read_file_pattern(struct tom
 			break;
 		}
 	}
-	up_read(&tomoyo_pattern_list_lock);
+	up_read(&tomoyo_policy_lock);
+	if (done)
+		tomoyo_cleanup_file_pattern();
 	return done;
 }
 
 /* The list for "struct tomoyo_no_rewrite_entry". */
 static LIST_HEAD(tomoyo_no_rewrite_list);
-static DECLARE_RWSEM(tomoyo_no_rewrite_list_lock);
 
 /**
  * tomoyo_update_no_rewrite_entry - Update "struct tomoyo_no_rewrite_entry" list.
@@ -408,7 +443,7 @@ static int tomoyo_update_no_rewrite_entr
 	if (!saved_pattern)
 		return -ENOMEM;
 	/***** EXCLUSIVE SECTION START *****/
-	down_write(&tomoyo_no_rewrite_list_lock);
+	down_write(&tomoyo_policy_lock);
 	list_for_each_entry(ptr, &tomoyo_no_rewrite_list, list) {
 		if (ptr->pattern != saved_pattern)
 			continue;
@@ -424,10 +459,12 @@ static int tomoyo_update_no_rewrite_entr
 	if (!new_entry)
 		goto out;
 	new_entry->pattern = saved_pattern;
+	saved_pattern = NULL;
 	list_add_tail(&new_entry->list, &tomoyo_no_rewrite_list);
 	error = 0;
  out:
-	up_write(&tomoyo_no_rewrite_list_lock);
+	tomoyo_del_name(saved_pattern);
+	up_write(&tomoyo_policy_lock);
 	/***** EXCLUSIVE SECTION END *****/
 	return error;
 }
@@ -445,7 +482,7 @@ static bool tomoyo_is_no_rewrite_file(co
 	struct tomoyo_no_rewrite_entry *ptr;
 	bool found = false;
 
-	down_read(&tomoyo_no_rewrite_list_lock);
+	down_read(&tomoyo_policy_lock);
 	list_for_each_entry(ptr, &tomoyo_no_rewrite_list, list) {
 		if (ptr->is_deleted)
 			continue;
@@ -454,7 +491,7 @@ static bool tomoyo_is_no_rewrite_file(co
 		found = true;
 		break;
 	}
-	up_read(&tomoyo_no_rewrite_list_lock);
+	up_read(&tomoyo_policy_lock);
 	return found;
 }
 
@@ -471,6 +508,23 @@ int tomoyo_write_no_rewrite_policy(char 
 	return tomoyo_update_no_rewrite_entry(data, is_delete);
 }
 
+static void tomoyo_cleanup_no_rewrite(void)
+{
+	struct tomoyo_no_rewrite_entry *ptr;
+	struct tomoyo_no_rewrite_entry *tmp;
+	/***** EXCLUSIVE SECTION START *****/
+	down_write(&tomoyo_policy_lock);
+	list_for_each_entry_safe(ptr, tmp, &tomoyo_no_rewrite_list, list) {
+		if (!ptr->is_deleted || tomoyo_used_by_cookie(ptr))
+			continue;
+		list_del(&ptr->list);
+		tomoyo_del_name(ptr->pattern);
+		tomoyo_free_element(ptr);
+	}
+	up_write(&tomoyo_policy_lock);
+	/***** EXCLUSIVE SECTION END *****/
+}
+
 /**
  * tomoyo_read_no_rewrite_policy - Read "struct tomoyo_no_rewrite_entry" list.
  *
@@ -483,8 +537,9 @@ bool tomoyo_read_no_rewrite_policy(struc
 	struct list_head *pos;
 	bool done = true;
 
-	down_read(&tomoyo_no_rewrite_list_lock);
-	list_for_each_cookie(pos, head->read_var2, &tomoyo_no_rewrite_list) {
+	down_read(&tomoyo_policy_lock);
+	list_for_each_cookie(pos, head->read_var2.u.list,
+			     &tomoyo_no_rewrite_list) {
 		struct tomoyo_no_rewrite_entry *ptr;
 		ptr = list_entry(pos, struct tomoyo_no_rewrite_entry, list);
 		if (ptr->is_deleted)
@@ -495,7 +550,9 @@ bool tomoyo_read_no_rewrite_policy(struc
 			break;
 		}
 	}
-	up_read(&tomoyo_no_rewrite_list_lock);
+	up_read(&tomoyo_policy_lock);
+	if (done)
+		tomoyo_cleanup_no_rewrite();
 	return done;
 }
 
@@ -561,7 +618,7 @@ static int tomoyo_check_single_path_acl2
 	struct tomoyo_acl_info *ptr;
 	int error = -EPERM;
 
-	down_read(&tomoyo_domain_acl_info_list_lock);
+	down_read(&tomoyo_policy_lock);
 	list_for_each_entry(ptr, &domain->acl_info_list, list) {
 		struct tomoyo_single_path_acl_record *acl;
 		if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL)
@@ -580,7 +637,7 @@ static int tomoyo_check_single_path_acl2
 		error = 0;
 		break;
 	}
-	up_read(&tomoyo_domain_acl_info_list_lock);
+	up_read(&tomoyo_policy_lock);
 	return error;
 }
 
@@ -662,10 +719,17 @@ static int tomoyo_check_file_perm2(struc
 		return error;
 	if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) {
 		/* Don't use patterns for execute permission. */
-		const struct tomoyo_path_info *patterned_file = (perm != 1) ?
-			tomoyo_get_file_pattern(filename) : filename;
-		tomoyo_update_file_acl(patterned_file->name, perm,
-				       domain, false);
+		if (perm == 1) {
+			tomoyo_update_file_acl(filename->name, perm, domain,
+					       false);
+		} else {
+			struct tomoyo_cookie cookie;
+			tomoyo_add_cookie(&cookie, filename);
+			tomoyo_get_file_pattern(&cookie);
+			tomoyo_update_file_acl(cookie.u.path->name, perm,
+					       domain, false);
+			tomoyo_del_cookie(&cookie);
+		}
 	}
 	return 0;
 }
@@ -746,7 +810,7 @@ static int tomoyo_update_single_path_acl
 	if (!saved_filename)
 		return -ENOMEM;
 	/***** EXCLUSIVE SECTION START *****/
-	down_write(&tomoyo_domain_acl_info_list_lock);
+	down_write(&tomoyo_policy_lock);
 	if (is_delete)
 		goto delete;
 	list_for_each_entry(ptr, &domain->acl_info_list, list) {
@@ -776,6 +840,7 @@ static int tomoyo_update_single_path_acl
 	if (perm == (1 << TOMOYO_TYPE_READ_WRITE_ACL))
 		acl->perm |= rw_mask;
 	acl->filename = saved_filename;
+	saved_filename = NULL;
 	list_add_tail(&acl->head.list, &domain->acl_info_list);
 	error = 0;
 	goto out;
@@ -799,7 +864,8 @@ static int tomoyo_update_single_path_acl
 		break;
 	}
  out:
-	up_write(&tomoyo_domain_acl_info_list_lock);
+	tomoyo_del_name(saved_filename);
+	up_write(&tomoyo_policy_lock);
 	/***** EXCLUSIVE SECTION END *****/
 	return error;
 }
@@ -834,10 +900,13 @@ static int tomoyo_update_double_path_acl
 		return -EINVAL;
 	saved_filename1 = tomoyo_save_name(filename1);
 	saved_filename2 = tomoyo_save_name(filename2);
-	if (!saved_filename1 || !saved_filename2)
+	if (!saved_filename1 || !saved_filename2) {
+		tomoyo_del_name(saved_filename1);
+		tomoyo_del_name(saved_filename2);
 		return -ENOMEM;
+	}
 	/***** EXCLUSIVE SECTION START *****/
-	down_write(&tomoyo_domain_acl_info_list_lock);
+	down_write(&tomoyo_policy_lock);
 	if (is_delete)
 		goto delete;
 	list_for_each_entry(ptr, &domain->acl_info_list, list) {
@@ -862,7 +931,9 @@ static int tomoyo_update_double_path_acl
 		goto out;
 	acl->perm = perm;
 	acl->filename1 = saved_filename1;
+	saved_filename1 = NULL;
 	acl->filename2 = saved_filename2;
+	saved_filename2 = NULL;
 	list_add_tail(&acl->head.list, &domain->acl_info_list);
 	error = 0;
 	goto out;
@@ -883,7 +954,9 @@ static int tomoyo_update_double_path_acl
 		break;
 	}
  out:
-	up_write(&tomoyo_domain_acl_info_list_lock);
+	tomoyo_del_name(saved_filename1);
+	tomoyo_del_name(saved_filename2);
+	up_write(&tomoyo_policy_lock);
 	/***** EXCLUSIVE SECTION END *****/
 	return error;
 }
@@ -929,7 +1002,7 @@ static int tomoyo_check_double_path_acl(
 
 	if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE))
 		return 0;
-	down_read(&tomoyo_domain_acl_info_list_lock);
+	down_read(&tomoyo_policy_lock);
 	list_for_each_entry(ptr, &domain->acl_info_list, list) {
 		struct tomoyo_double_path_acl_record *acl;
 		if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL)
@@ -945,7 +1018,7 @@ static int tomoyo_check_double_path_acl(
 		error = 0;
 		break;
 	}
-	up_read(&tomoyo_domain_acl_info_list_lock);
+	up_read(&tomoyo_policy_lock);
 	return error;
 }
 
@@ -980,8 +1053,12 @@ static int tomoyo_check_single_path_perm
 		       tomoyo_get_msg(is_enforce), msg, filename->name,
 		       tomoyo_get_last_name(domain));
 	if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) {
-		const char *name = tomoyo_get_file_pattern(filename)->name;
-		tomoyo_update_single_path_acl(operation, name, domain, false);
+		struct tomoyo_cookie cookie;
+		tomoyo_add_cookie(&cookie, filename);
+		tomoyo_get_file_pattern(&cookie);
+		tomoyo_update_single_path_acl(operation, cookie.u.path->name,
+					      domain, false);
+		tomoyo_del_cookie(&cookie);
 	}
 	if (!is_enforce)
 		error = 0;
@@ -1227,10 +1304,17 @@ int tomoyo_check_2path_perm(struct tomoy
 		       msg, buf1->name, buf2->name,
 		       tomoyo_get_last_name(domain));
 	if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) {
-		const char *name1 = tomoyo_get_file_pattern(buf1)->name;
-		const char *name2 = tomoyo_get_file_pattern(buf2)->name;
-		tomoyo_update_double_path_acl(operation, name1, name2, domain,
+		struct tomoyo_cookie cookie1;
+		struct tomoyo_cookie cookie2;
+		tomoyo_add_cookie(&cookie1, buf1);
+		tomoyo_add_cookie(&cookie2, buf2);
+		tomoyo_get_file_pattern(&cookie1);
+		tomoyo_get_file_pattern(&cookie2);
+		tomoyo_update_double_path_acl(operation, cookie1.u.path->name,
+					      cookie2.u.path->name, domain,
 					      false);
+		tomoyo_del_cookie(&cookie1);
+		tomoyo_del_cookie(&cookie2);
 	}
  out:
 	tomoyo_free(buf1);
--- security-testing-2.6.git.orig/security/tomoyo/realpath.c
+++ security-testing-2.6.git/security/tomoyo/realpath.c
@@ -194,68 +194,51 @@ char *tomoyo_realpath_nofollow(const cha
 }
 
 /* Memory allocated for non-string data. */
-static unsigned int tomoyo_allocated_memory_for_elements;
+static atomic_t tomoyo_allocated_memory_for_elements;
 /* Quota for holding non-string data. */
 static unsigned int tomoyo_quota_for_elements;
 
 /**
- * tomoyo_alloc_element - Allocate permanent memory for structures.
+ * tomoyo_alloc_element - Allocate memory for structures.
  *
  * @size: Size in bytes.
  *
  * Returns pointer to allocated memory on success, NULL otherwise.
  *
- * Memory has to be zeroed.
- * The RAM is chunked, so NEVER try to kfree() the returned pointer.
+ * Memory are zeroed.
  */
 void *tomoyo_alloc_element(const unsigned int size)
 {
-	static char *buf;
-	static DEFINE_MUTEX(lock);
-	static unsigned int buf_used_len = PATH_MAX;
-	char *ptr = NULL;
-	/*Assumes sizeof(void *) >= sizeof(long) is true. */
-	const unsigned int word_aligned_size
-		= roundup(size, max(sizeof(void *), sizeof(long)));
-	if (word_aligned_size > PATH_MAX)
-		return NULL;
-	/***** EXCLUSIVE SECTION START *****/
-	mutex_lock(&lock);
-	if (buf_used_len + word_aligned_size > PATH_MAX) {
-		if (!tomoyo_quota_for_elements ||
-		    tomoyo_allocated_memory_for_elements
-		    + PATH_MAX <= tomoyo_quota_for_elements)
-			ptr = kzalloc(PATH_MAX, GFP_KERNEL);
-		if (!ptr) {
-			printk(KERN_WARNING "ERROR: Out of memory "
-			       "for tomoyo_alloc_element().\n");
-			if (!tomoyo_policy_loaded)
-				panic("MAC Initialization failed.\n");
-		} else {
-			buf = ptr;
-			tomoyo_allocated_memory_for_elements += PATH_MAX;
-			buf_used_len = word_aligned_size;
-			ptr = buf;
-		}
-	} else if (word_aligned_size) {
-		int i;
-		ptr = buf + buf_used_len;
-		buf_used_len += word_aligned_size;
-		for (i = 0; i < word_aligned_size; i++) {
-			if (!ptr[i])
-				continue;
-			printk(KERN_ERR "WARNING: Reserved memory was tainted! "
-			       "The system might go wrong.\n");
-			ptr[i] = '\0';
-		}
+	char *ptr = kzalloc(size, GFP_KERNEL);
+	int len = ptr ? ksize(ptr) : 0;
+	atomic_add(len, &tomoyo_allocated_memory_for_elements);
+	if (!len ||
+	    (tomoyo_quota_for_elements &&
+	     atomic_read(&tomoyo_allocated_memory_for_elements)
+	     > tomoyo_quota_for_elements)) {
+		kfree(ptr);
+		ptr = NULL;
+		atomic_sub(len, &tomoyo_allocated_memory_for_elements);
+		printk(KERN_WARNING "ERROR: Out of memory for %s().\n",
+		       __func__);
+		if (!tomoyo_policy_loaded)
+			panic("MAC Initialization failed.\n");
 	}
-	mutex_unlock(&lock);
-	/***** EXCLUSIVE SECTION END *****/
 	return ptr;
 }
 
+void tomoyo_free_element(void *ptr)
+{
+	int len;
+	if (!ptr)
+		return;
+	len = ksize(ptr);
+	kfree(ptr);
+	atomic_sub(len, &tomoyo_allocated_memory_for_elements);
+}
+
 /* Memory allocated for string data in bytes. */
-static unsigned int tomoyo_allocated_memory_for_savename;
+static atomic_t tomoyo_allocated_memory_for_savename;
 /* Quota for holding string data in bytes. */
 static unsigned int tomoyo_quota_for_savename;
 
@@ -269,44 +252,27 @@ static unsigned int tomoyo_quota_for_sav
 /* Structure for string data. */
 struct tomoyo_name_entry {
 	struct list_head list;
+	atomic_t users;
 	struct tomoyo_path_info entry;
 };
 
-/* Structure for available memory region. */
-struct tomoyo_free_memory_block_list {
-	struct list_head list;
-	char *ptr;             /* Pointer to a free area. */
-	int len;               /* Length of the area.     */
-};
-
-/*
- * The list for "struct tomoyo_name_entry".
- *
- * This list is updated only inside tomoyo_save_name(), thus
- * no global mutex exists.
- */
+/* The list for "struct tomoyo_name_entry". */
 static struct list_head tomoyo_name_list[TOMOYO_MAX_HASH];
+static DEFINE_MUTEX(tomoyo_name_list_lock);
 
 /**
- * tomoyo_save_name - Allocate permanent memory for string data.
+ * tomoyo_save_name - Allocate shared memory for string data.
  *
- * @name: The string to store into the permernent memory.
+ * @name: The string to add or find.
  *
  * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise.
- *
- * The RAM is shared, so NEVER try to modify or kfree() the returned name.
  */
 const struct tomoyo_path_info *tomoyo_save_name(const char *name)
 {
-	static LIST_HEAD(fmb_list);
-	static DEFINE_MUTEX(lock);
 	struct tomoyo_name_entry *ptr;
 	unsigned int hash;
-	/* fmb contains available size in bytes.
-	   fmb is removed from the fmb_list when fmb->len becomes 0. */
-	struct tomoyo_free_memory_block_list *fmb;
 	int len;
-	char *cp;
+	int allocated_len;
 
 	if (!name)
 		return NULL;
@@ -318,74 +284,89 @@ const struct tomoyo_path_info *tomoyo_sa
 	}
 	hash = full_name_hash((const unsigned char *) name, len - 1);
 	/***** EXCLUSIVE SECTION START *****/
-	mutex_lock(&lock);
+	mutex_lock(&tomoyo_name_list_lock);
 	list_for_each_entry(ptr, &tomoyo_name_list[hash % TOMOYO_MAX_HASH],
-			     list) {
-		if (hash == ptr->entry.hash && !strcmp(name, ptr->entry.name))
-			goto out;
-	}
-	list_for_each_entry(fmb, &fmb_list, list) {
-		if (len <= fmb->len)
-			goto ready;
+			    list) {
+		if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name))
+			continue;
+		atomic_inc(&ptr->users);
+		goto out;
 	}
-	if (!tomoyo_quota_for_savename ||
-	    tomoyo_allocated_memory_for_savename + PATH_MAX
-	    <= tomoyo_quota_for_savename)
-		cp = kzalloc(PATH_MAX, GFP_KERNEL);
-	else
-		cp = NULL;
-	fmb = kzalloc(sizeof(*fmb), GFP_KERNEL);
-	if (!cp || !fmb) {
-		kfree(cp);
-		kfree(fmb);
-		printk(KERN_WARNING "ERROR: Out of memory "
-		       "for tomoyo_save_name().\n");
+	ptr = kmalloc(sizeof(*ptr) + len, GFP_KERNEL);
+	allocated_len = ptr ? ksize(ptr) : 0;
+	if (!allocated_len ||
+	    (tomoyo_quota_for_savename &&
+	     atomic_read(&tomoyo_allocated_memory_for_savename)
+	     + allocated_len > tomoyo_quota_for_savename)) {
+		kfree(ptr);
+		ptr = NULL;
+		printk(KERN_WARNING "ERROR: Out of memory for %s().\n",
+		       __func__);
 		if (!tomoyo_policy_loaded)
 			panic("MAC Initialization failed.\n");
-		ptr = NULL;
 		goto out;
 	}
-	tomoyo_allocated_memory_for_savename += PATH_MAX;
-	list_add(&fmb->list, &fmb_list);
-	fmb->ptr = cp;
-	fmb->len = PATH_MAX;
- ready:
-	ptr = tomoyo_alloc_element(sizeof(*ptr));
-	if (!ptr)
-		goto out;
-	ptr->entry.name = fmb->ptr;
-	memmove(fmb->ptr, name, len);
+	atomic_add(allocated_len, &tomoyo_allocated_memory_for_savename);
+	ptr->entry.name = ((char *) ptr) + sizeof(*ptr);
+	memmove((char *) ptr->entry.name, name, len);
+	atomic_set(&ptr->users, 1);
 	tomoyo_fill_path_info(&ptr->entry);
-	fmb->ptr += len;
-	fmb->len -= len;
 	list_add_tail(&ptr->list, &tomoyo_name_list[hash % TOMOYO_MAX_HASH]);
-	if (fmb->len == 0) {
-		list_del(&fmb->list);
-		kfree(fmb);
-	}
  out:
-	mutex_unlock(&lock);
+	mutex_unlock(&tomoyo_name_list_lock);
 	/***** EXCLUSIVE SECTION END *****/
 	return ptr ? &ptr->entry : NULL;
 }
 
 /**
+ * tomoyo_del_name - Delete shared memory for string data.
+ *
+ * @name: Pointer to "struct tomoyo_path_info".
+ */
+void tomoyo_del_name(const struct tomoyo_path_info *name)
+{
+	struct tomoyo_name_entry *ptr;
+
+	if (!name)
+		return;
+	/***** EXCLUSIVE SECTION START *****/
+	mutex_lock(&tomoyo_name_list_lock);
+	list_for_each_entry(ptr, &tomoyo_name_list[name->hash %
+						   TOMOYO_MAX_HASH], list) {
+		if (tomoyo_pathcmp(name, &ptr->entry))
+			continue;
+		if (atomic_dec_and_test(&ptr->users)) {
+			int len = ksize(ptr);
+			list_del(&ptr->list);
+			kfree(ptr);
+			atomic_sub(len, &tomoyo_allocated_memory_for_savename);
+		}
+		break;
+	}
+	mutex_unlock(&tomoyo_name_list_lock);
+	/***** EXCLUSIVE SECTION END *****/
+}
+
+/**
  * tomoyo_realpath_init - Initialize realpath related code.
  */
 void __init tomoyo_realpath_init(void)
 {
 	int i;
+	struct tomoyo_cookie cookie;
 
 	BUILD_BUG_ON(TOMOYO_MAX_PATHNAME_LEN > PATH_MAX);
 	for (i = 0; i < TOMOYO_MAX_HASH; i++)
 		INIT_LIST_HEAD(&tomoyo_name_list[i]);
 	INIT_LIST_HEAD(&tomoyo_kernel_domain.acl_info_list);
+	/* No lock because this domain is not deletable. */
 	tomoyo_kernel_domain.domainname = tomoyo_save_name(TOMOYO_ROOT_NAME);
 	list_add_tail(&tomoyo_kernel_domain.list, &tomoyo_domain_list);
-	down_read(&tomoyo_domain_list_lock);
-	if (tomoyo_find_domain(TOMOYO_ROOT_NAME) != &tomoyo_kernel_domain)
+	down_read(&tomoyo_policy_lock);
+	if (!tomoyo_find_domain(TOMOYO_ROOT_NAME, &cookie) ||
+	    cookie.u.domain != &tomoyo_kernel_domain)
 		panic("Can't register tomoyo_kernel_domain");
-	up_read(&tomoyo_domain_list_lock);
+	up_read(&tomoyo_policy_lock);
 }
 
 /* Memory allocated for temporary purpose. */
@@ -432,9 +413,9 @@ int tomoyo_read_memory_counter(struct to
 {
 	if (!head->read_eof) {
 		const unsigned int shared
-			= tomoyo_allocated_memory_for_savename;
+			= atomic_read(&tomoyo_allocated_memory_for_savename);
 		const unsigned int private
-			= tomoyo_allocated_memory_for_elements;
+			= atomic_read(&tomoyo_allocated_memory_for_elements);
 		const unsigned int dynamic
 			= atomic_read(&tomoyo_dynamic_memory_size);
 		char buffer[64];
@@ -480,3 +461,64 @@ int tomoyo_write_memory_quota(struct tom
 		tomoyo_quota_for_elements = size;
 	return 0;
 }
+
+/* List of pointers referenced by cookies. */
+static LIST_HEAD(tomoyo_cookie_list);
+static DEFINE_RWLOCK(tomoyo_cookie_list_lock);
+
+/**
+ * tomoyo_add_cookie - Add a cookie to cookie list.
+ *
+ * @cookie: Pointer to "struct tomoyo_cookie".
+ * @ptr:    Pointer to assign.
+ */
+void tomoyo_add_cookie(struct tomoyo_cookie *cookie, const void *ptr)
+{
+	unsigned long flags;
+	if (!cookie)
+		return;
+	tomoyo_update_cookie(cookie, ptr);
+	write_lock_irqsave(&tomoyo_cookie_list_lock, flags);
+	list_add_tail(&cookie->list, &tomoyo_cookie_list);
+	write_unlock_irqrestore(&tomoyo_cookie_list_lock, flags);
+}
+
+/**
+ * tomoyo_del_cookie - Delete a cookie from cookie list.
+ *
+ * @cookie: Pointer to "struct tomoyo_cookie".
+ */
+void tomoyo_del_cookie(struct tomoyo_cookie *cookie)
+{
+	unsigned long flags;
+	if (!cookie)
+		return;
+	write_lock_irqsave(&tomoyo_cookie_list_lock, flags);
+	list_del(&cookie->list);
+	write_unlock_irqrestore(&tomoyo_cookie_list_lock, flags);
+}
+
+/**
+ * tomoyo_used_by_cookie - Check whether the given pointer is referenced by a cookie or not.
+ *
+ * @ptr: Pointer to check.
+ *
+ * Returns true if @ptr is in use, false otherwise.
+ *
+ * Caller must hold tomoyo_policy_lock for writing.
+ */
+bool tomoyo_used_by_cookie(const void *ptr)
+{
+	unsigned long flags;
+	struct tomoyo_cookie *cookie;
+	bool in_use = false;
+	read_lock_irqsave(&tomoyo_cookie_list_lock, flags);
+	list_for_each_entry(cookie, &tomoyo_cookie_list, list) {
+		if (ptr != cookie->u.ptr)
+			continue;
+		in_use = true;
+		break;
+	}
+	read_unlock_irqrestore(&tomoyo_cookie_list_lock, flags);
+	return in_use;
+}
--- security-testing-2.6.git.orig/security/tomoyo/realpath.h
+++ security-testing-2.6.git/security/tomoyo/realpath.h
@@ -36,18 +36,6 @@ char *tomoyo_realpath_nofollow(const cha
 /* Same with tomoyo_realpath() except that the pathname is already solved. */
 char *tomoyo_realpath_from_path(struct path *path);
 
-/*
- * Allocate memory for ACL entry.
- * The RAM is chunked, so NEVER try to kfree() the returned pointer.
- */
-void *tomoyo_alloc_element(const unsigned int size);
-
-/*
- * Keep the given name on the RAM.
- * The RAM is shared, so NEVER try to modify or kfree() the returned name.
- */
-const struct tomoyo_path_info *tomoyo_save_name(const char *name);
-
 /* Allocate memory for temporary use (e.g. permission checks). */
 void *tomoyo_alloc(const size_t size);
 
@@ -63,4 +51,35 @@ int tomoyo_write_memory_quota(struct tom
 /* Initialize realpath related code. */
 void __init tomoyo_realpath_init(void);
 
+/* Allocate memory for ACL entry. */
+void *tomoyo_alloc_element(const unsigned int size);
+/* Delete memory for ACL entry. */
+void tomoyo_free_element(void *ptr);
+
+/* Allocate memory for the given name. */
+const struct tomoyo_path_info *tomoyo_save_name(const char *name);
+/* Delete memory for the given name. */
+void tomoyo_del_name(const struct tomoyo_path_info *name);
+
+/* Add a cookie to cookie list. */
+void tomoyo_add_cookie(struct tomoyo_cookie *cookie, const void *ptr);
+/**
+ * tomoyo_update_cookie - Assign the given pointer to a cookie.
+ *
+ * @cookie: Pointer to "struct tomoyo_cookie".
+ * @ptr:    Pointer to assign.
+ *
+ * Caller must hold tomoyo_policy_lock for writing unless @ptr is NULL or
+ * @ptr is already in cookie list.
+ */
+static inline void tomoyo_update_cookie(struct tomoyo_cookie *cookie,
+					const void *ptr)
+{
+	cookie->u.ptr = ptr;
+}
+/* Delete a cookie from cookie list. */
+void tomoyo_del_cookie(struct tomoyo_cookie *cookie);
+/* Check whether the given pointer is referenced by a cookie or not. */
+bool tomoyo_used_by_cookie(const void *ptr);
+
 #endif /* !defined(_SECURITY_TOMOYO_REALPATH_H) */
--- security-testing-2.6.git.orig/security/tomoyo/tomoyo.c
+++ security-testing-2.6.git/security/tomoyo/tomoyo.c
@@ -17,14 +17,23 @@
 static int tomoyo_cred_prepare(struct cred *new, const struct cred *old,
 			       gfp_t gfp)
 {
-	/*
-	 * Since "struct tomoyo_domain_info *" is a sharable pointer,
-	 * we don't need to duplicate.
-	 */
-	new->security = old->security;
+	struct tomoyo_cookie *cookie = kzalloc(sizeof(*cookie), gfp);
+
+	if (!cookie)
+		return -ENOMEM;
+	tomoyo_add_cookie(cookie,
+			  ((struct tomoyo_cookie *) old->security)->u.ptr);
+	new->security = cookie;
 	return 0;
 }
 
+static void tomoyo_cred_free(struct cred *cred)
+{
+	struct tomoyo_cookie *cookie = cred->security;
+	tomoyo_del_cookie(cookie);
+	kfree(cookie);
+}
+
 static int tomoyo_bprm_set_creds(struct linux_binprm *bprm)
 {
 	/*
@@ -43,26 +52,21 @@ static int tomoyo_bprm_set_creds(struct 
 	 * Tell tomoyo_bprm_check_security() is called for the first time of an
 	 * execve operation.
 	 */
-	bprm->cred->security = NULL;
+	((struct tomoyo_cookie *) bprm->cred->security)->u.domain = NULL;
 	return 0;
 }
 
 static int tomoyo_bprm_check_security(struct linux_binprm *bprm)
 {
-	struct tomoyo_domain_info *domain = bprm->cred->security;
+	struct tomoyo_domain_info *domain = ((struct tomoyo_cookie *)
+					     bprm->cred->security)->u.domain;
 
 	/*
 	 * Execute permission is checked against pathname passed to do_execve()
 	 * using current domain.
 	 */
-	if (!domain) {
-		struct tomoyo_domain_info *next_domain = NULL;
-		int retval = tomoyo_find_next_domain(bprm, &next_domain);
-
-		if (!retval)
-			bprm->cred->security = next_domain;
-		return retval;
-	}
+	if (!domain)
+		return tomoyo_find_next_domain(bprm);
 	/*
 	 * Read permission is checked against interpreters using next domain.
 	 * '1' is the result of open_to_namei_flags(O_RDONLY).
@@ -259,6 +263,7 @@ static int tomoyo_dentry_open(struct fil
 static struct security_operations tomoyo_security_ops = {
 	.name                = "tomoyo",
 	.cred_prepare        = tomoyo_cred_prepare,
+	.cred_free           = tomoyo_cred_free,
 	.bprm_set_creds      = tomoyo_bprm_set_creds,
 	.bprm_check_security = tomoyo_bprm_check_security,
 #ifdef CONFIG_SYSCTL
@@ -279,6 +284,7 @@ static struct security_operations tomoyo
 static int __init tomoyo_init(void)
 {
 	struct cred *cred = (struct cred *) current_cred();
+	struct tomoyo_cookie *cookie;
 
 	if (!security_module_enable(&tomoyo_security_ops))
 		return 0;
@@ -286,7 +292,9 @@ static int __init tomoyo_init(void)
 	if (register_security(&tomoyo_security_ops))
 		panic("Failure registering TOMOYO Linux");
 	printk(KERN_INFO "TOMOYO Linux initialized\n");
-	cred->security = &tomoyo_kernel_domain;
+	cookie = kzalloc(sizeof(*cookie), GFP_KERNEL);
+	tomoyo_add_cookie(cookie, &tomoyo_kernel_domain);
+	cred->security = cookie;
 	tomoyo_realpath_init();
 	return 0;
 }
--- security-testing-2.6.git.orig/security/tomoyo/tomoyo.h
+++ security-testing-2.6.git/security/tomoyo/tomoyo.h
@@ -33,8 +33,7 @@ int tomoyo_check_2path_perm(struct tomoy
 			    struct path *path2);
 int tomoyo_check_rewrite_permission(struct tomoyo_domain_info *domain,
 				    struct file *filp);
-int tomoyo_find_next_domain(struct linux_binprm *bprm,
-			    struct tomoyo_domain_info **next_domain);
+int tomoyo_find_next_domain(struct linux_binprm *bprm);
 
 /* Index numbers for Access Controls. */
 
@@ -85,18 +84,14 @@ int tomoyo_find_next_domain(struct linux
 
 extern struct tomoyo_domain_info tomoyo_kernel_domain;
 
-static inline struct tomoyo_domain_info *tomoyo_domain(void)
-{
-	return current_cred()->security;
-}
-
-/* Caller holds tasklist_lock spinlock. */
+/* Caller calls rcu_read_lock()/rcu_read_unlock(). */
 static inline struct tomoyo_domain_info *tomoyo_real_domain(struct task_struct
 							    *task)
 {
 	/***** CRITICAL SECTION START *****/
 	const struct cred *cred = get_task_cred(task);
-	struct tomoyo_domain_info *domain = cred->security;
+	struct tomoyo_domain_info *domain = ((struct tomoyo_cookie *)
+					     cred->security)->u.domain;
 
 	put_cred(cred);
 	return domain;

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [TOMOYO] Add garbage collector support.
  2009-05-07 11:42                 ` [TOMOYO] Add garbage collector support Tetsuo Handa
@ 2009-05-08  1:43                   ` James Morris
  2009-05-08  2:10                     ` Tetsuo Handa
  2009-05-08  9:32                   ` Pavel Machek
  1 sibling, 1 reply; 34+ messages in thread
From: James Morris @ 2009-05-08  1:43 UTC (permalink / raw)
  To: Tetsuo Handa; +Cc: pavel, linux-security-module, linux-kernel

On Thu, 7 May 2009, Tetsuo Handa wrote:

> Now, TOMOYO can release memory. :-)
> 
> Attached patch is for security-testing-2.6#next.
> James, it is possible to apply below commits to security-testing-2.6#next ?

It's an invasive patch.  How much testing and review has this had by your 
team?

> I get a lot of warning messages in my environment.

Please elaborate.


- James
-- 
James Morris
<jmorris@namei.org>

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [TOMOYO] Add garbage collector support.
  2009-05-08  1:43                   ` James Morris
@ 2009-05-08  2:10                     ` Tetsuo Handa
  2009-05-08  8:26                       ` James Morris
  0 siblings, 1 reply; 34+ messages in thread
From: Tetsuo Handa @ 2009-05-08  2:10 UTC (permalink / raw)
  To: jmorris; +Cc: pavel, linux-security-module, linux-kernel

James Morris wrote:
> > James, it is possible to apply below commits to security-testing-2.6#next ?
> > I get a lot of warning messages in my environment.
> 
> Please elaborate.

Without commits

  mm: pass correct mm when growing stack
  Revert "kobject: don't block for each kobject_uevent".
  x86: clean up old gcc warnings

I get compiler warnings

  # make init/main.o
  scripts/kconfig/conf -s arch/x86/Kconfig
    CHK     include/linux/version.h
    CHK     include/linux/utsrelease.h
    SYMLINK include/asm -> include/asm-x86
    CALL    scripts/checksyscalls.sh
    CC      init/main.o
  In file included from /usr/src/all/security-testing-2.6.git/arch/x86/include/asm/page.h:8,
                   from /usr/src/all/security-testing-2.6.git/arch/x86/include/asm/processor.h:18,
                   from include/linux/prefetch.h:14,
                   from include/linux/list.h:6,
                   from include/linux/module.h:9,
                   from init/main.c:13:
  /usr/src/all/security-testing-2.6.git/arch/x86/include/asm/page_types.h:48: warning: parameter has incomplete type
  /usr/src/all/security-testing-2.6.git/arch/x86/include/asm/page_types.h:50: warning: parameter has incomplete type

and runtime warnings

  ------------[ cut here ]------------
  WARNING: at security/security.c:217 security_vm_enough_memory+0x9b/0xb0()
  Hardware name: VMware Virtual Platform
  Modules linked in: pcnet32 crc32
  Pid: 3277, comm: khelper Not tainted 2.6.29 #3
  Call Trace:
   [<c015f400>] ? zap_locks+0x110/0x130
   [<c015e5fd>] warn_slowpath+0x8d/0xf0
   [<c019b2ec>] ? validate_chain+0x3fc/0x540
   [<c019b2ec>] ? validate_chain+0x3fc/0x540
   [<c019d79c>] ? __lock_acquire+0x29c/0x8b0
   [<c019f159>] ? __lock_acquired+0x109/0x1c0
   [<c035bbdb>] security_vm_enough_memory+0x9b/0xb0
   [<c02089bb>] acct_stack_growth+0xcb/0x190
   [<c0208ba1>] expand_downwards+0x121/0x1a0
   [<c0208c3d>] expand_stack+0xd/0x10
   [<c0208cdd>] find_extend_vma+0x9d/0x130
   [<c01ff5d5>] __get_user_pages+0x95/0x6c0
   [<c01ffc73>] get_user_pages+0x73/0x90
   [<c0233cd8>] get_arg_page+0x48/0x130
   [<c02342a5>] copy_strings+0x165/0x2f0
   [<c02366ba>] do_execve+0x31a/0x900
   [<c010252a>] sys_execve+0x5a/0xb0
   [<c01040b4>] syscall_call+0x7/0xb
   [<c010b624>] ? kernel_execve+0x24/0x30
   [<c017ab73>] ? ____call_usermodehelper+0x103/0x190
   [<c017aa70>] ? ____call_usermodehelper+0x0/0x190
   [<c0104a73>] ? kernel_thread_helper+0x7/0x10
  ---[ end trace 636cdcc028137283 ]---

in my environment.

These commits are already in 2.6.30-rc4.
These warnings will disappear when security-testing-2.6#next is refreshed
using 2.6.30-rcX . But security-testing-2.6#next is using 2.6.29.
Thus, I wished these commits applied to security-testing-2.6#next
if there is no problem.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [TOMOYO] Add garbage collector support.
  2009-05-08  2:10                     ` Tetsuo Handa
@ 2009-05-08  8:26                       ` James Morris
  2009-05-08  9:22                         ` Tetsuo Handa
  0 siblings, 1 reply; 34+ messages in thread
From: James Morris @ 2009-05-08  8:26 UTC (permalink / raw)
  To: Tetsuo Handa; +Cc: pavel, linux-security-module, linux-kernel

On Fri, 8 May 2009, Tetsuo Handa wrote:

> James Morris wrote:
> > > James, it is possible to apply below commits to security-testing-2.6#next ?
> > > I get a lot of warning messages in my environment.
> > 
> > Please elaborate.
> 
> Without commits
> 
>   mm: pass correct mm when growing stack
>   Revert "kobject: don't block for each kobject_uevent".
>   x86: clean up old gcc warnings
> 
> I get compiler warnings
> 
[...]

Ok, I've merged #next with current Linus.

-- 
James Morris
<jmorris@namei.org>

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [TOMOYO] Add garbage collector support.
  2009-05-08  8:26                       ` James Morris
@ 2009-05-08  9:22                         ` Tetsuo Handa
  0 siblings, 0 replies; 34+ messages in thread
From: Tetsuo Handa @ 2009-05-08  9:22 UTC (permalink / raw)
  To: jmorris; +Cc: pavel, linux-security-module, linux-kernel

James Morris wrote:
> Ok, I've merged #next with current Linus.

Thank you for your time.
Now, I'm testing the garbage collector patch.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [TOMOYO] Add garbage collector support.
  2009-05-07 11:42                 ` [TOMOYO] Add garbage collector support Tetsuo Handa
  2009-05-08  1:43                   ` James Morris
@ 2009-05-08  9:32                   ` Pavel Machek
  1 sibling, 0 replies; 34+ messages in thread
From: Pavel Machek @ 2009-05-08  9:32 UTC (permalink / raw)
  To: Tetsuo Handa; +Cc: jmorris, linux-security-module, linux-kernel

> 
> Now, TOMOYO can release memory. :-)


Thanks!

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [PATCH] TOMOYO: Add garbage collector support. (v2)
  2009-05-06 12:16               ` Tetsuo Handa
  2009-05-07 11:42                 ` [TOMOYO] Add garbage collector support Tetsuo Handa
@ 2009-05-14 12:08                 ` Tetsuo Handa
  2009-05-15  1:49                   ` James Morris
  1 sibling, 1 reply; 34+ messages in thread
From: Tetsuo Handa @ 2009-05-14 12:08 UTC (permalink / raw)
  To: jmorris, linux-security-module; +Cc: linux-kernel

A process who is reading/writing list elements has pointers which point to
(possibly marked-as-deleted) list elements and releases a lock when the process
leaves the kernel.

As of now, TOMOYO cannot release memory used by marked-as-deleted list elements
because TOMOYO does not manage list of pointers.

This patch makes TOMOYO to manage list of pointers and allows an administrator
release memory used by marked-as-deleted list elements.

Also, according to KOSAKI Motohiro's comment
( http://lkml.org/lkml/2009/5/10/176 ), I moved TOMOYO's
kmalloc(GFP_KERNEL)/kfree() calls to outside the rw_semaphore.

Attached patch is tested on security-testing-2.6#next.

Regards.
----------------------------------------
TOMOYO: Add garbage collector support.

A process who is reading/writing list elements has pointers which point to
(possibly marked-as-deleted) list elements and releases a lock when the process
leaves the kernel.

As of now, TOMOYO cannot release memory used by marked-as-deleted list elements
because TOMOYO does not manage list of pointers.

This patch makes TOMOYO to manage list of pointers and allows an administrator
release memory used by marked-as-deleted list elements.

Also, this patch makes TOMOYO's kmalloc(GFP_KERNEL)/kfree() calls go outside
the rw_semaphore.

Approach:

  Define a cookie as

    struct tomoyo_cookie {
    	struct list_head list;
    	union {
    		const void *ptr;
    		struct list_head *list;
    		struct tomoyo_domain_info *domain;
    		const struct tomoyo_path_info *path;
    	} u;
    };

  and add the cookie to the cookie's list using

    void tomoyo_add_cookie(struct tomoyo_cookie *cookie, const void *ptr);

  and delete the cookie from the cookie's list using

    void tomoyo_del_cookie(struct tomoyo_cookie *cookie);

  and update the "cookie->u.{ptr,list,domain,path}" between
  down_read(&tomoyo_policy_lock); and up_read(&tomoyo_policy_lock); .

  To keep the cookie's list up-to-date, tomoyo_add_cookie() and
  tomoyo_del_cookie() take write lock of tomoyo_cookie_list_lock spinlock and
  tomoyo_used_by_cookie() takes read lock of tomoyo_cookie_list_lock spinlock.

  The garbage collector function scans the cookie's list using

    bool tomoyo_used_by_cookie(const void *ptr);

  between down_write(&tomoyo_policy_lock); and up_write(&tomoyo_policy_lock);
  to determine whether "ptr" is kfree()able or not.

  In this way, the garbage collector shall not release "ptr" stored in a cookie
  in the cookie's list.

Memory Management Rules:
  
  When reading list elements, a process takes tomoyo_policy_lock for reading.
  When writing list elements, a process takes tomoyo_policy_lock for writing.

  "struct tomoyo_io_buffer" remembers pointer to list elements.
  Thus, TOMOYO memorizes the address of
    "struct tomoyo_io_buffer"->read_cookie1
    "struct tomoyo_io_buffer"->read_cookie2
    "struct tomoyo_io_buffer"->write_cookie1
  when a file in /sys/kernel/security/tomoyo/ interface is opened and forgets
  them when that file is closed.

  "struct task_struct"->cred->security also remembers pointer to list elements.
  Thus, TOMOYO memorizes the address of cred->security at
  security_cred_prepare() and forgets it at security_cred_free().

  When /sys/kernel/security/tomoyo/ interface opened for writing is closed,
  a garbage collector function is called. The garbage collector function takes
  tomoyo_policy_lock for writing and traverses the lists and releases elements
  if that element has is_deleted flag set and that element is no longer used.

  Since strings are likely referenced by multiple list elements, this patch
  assigns a refcounter to each string.
  The policy add/del function increments the refcounter only if the element is
  added to the list. The garbage collector function decrements the refcounter
  only if the element is not referred by a process.
  The garbage collector function releases memory of the string if the string's
  refcounter becomes 0.

Signed-off-by: Kentaro Takeda <takedakn@nttdata.co.jp>
Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Signed-off-by: Toshiharu Harada <haradats@nttdata.co.jp>
---
 security/tomoyo/common.c   |  456 +++++++++++++++++++-----------------
 security/tomoyo/common.h   |  134 ++++++++--
 security/tomoyo/domain.c   |  437 +++++++++++++---------------------
 security/tomoyo/file.c     |  369 +++++++++++++++--------------
 security/tomoyo/realpath.c |  567 ++++++++++++++++++++++++++++++++++-----------
 security/tomoyo/realpath.h |   25 +
 security/tomoyo/tomoyo.c   |   40 +--
 security/tomoyo/tomoyo.h   |   13 -
 8 files changed, 1190 insertions(+), 851 deletions(-)

--- security-testing-2.6.git.orig/security/tomoyo/common.c
+++ security-testing-2.6.git/security/tomoyo/common.c
@@ -12,8 +12,8 @@
 #include <linux/uaccess.h>
 #include <linux/security.h>
 #include <linux/hardirq.h>
-#include "realpath.h"
 #include "common.h"
+#include "realpath.h"
 #include "tomoyo.h"
 
 /* Has loading policy done? */
@@ -23,6 +23,7 @@ bool tomoyo_policy_loaded;
 static const char *tomoyo_mode_4[4] = {
 	"disabled", "learning", "permissive", "enforcing"
 };
+
 /* String table for functionality that takes 2 modes. */
 static const char *tomoyo_mode_2[4] = {
 	"disabled", "enabled", "enabled", "enabled"
@@ -52,11 +53,14 @@ static bool tomoyo_manage_by_non_root;
 
 /* Open operation for /sys/kernel/security/tomoyo/ interface. */
 static int tomoyo_open_control(const u8 type, struct file *file);
+
 /* Close /sys/kernel/security/tomoyo/ interface. */
 static int tomoyo_close_control(struct file *file);
+
 /* Read operation for /sys/kernel/security/tomoyo/ interface. */
 static int tomoyo_read_control(struct file *file, char __user *buffer,
 			       const int buffer_len);
+
 /* Write operation for /sys/kernel/security/tomoyo/ interface. */
 static int tomoyo_write_control(struct file *file, const char __user *buffer,
 				const int buffer_len);
@@ -326,25 +330,30 @@ bool tomoyo_is_domain_def(const unsigned
  * tomoyo_find_domain - Find a domain by the given name.
  *
  * @domainname: The domainname to find.
+ * @cookie:     Pointer to "struct tomoyo_cookie".
  *
- * Caller must call down_read(&tomoyo_domain_list_lock); or
- * down_write(&tomoyo_domain_list_lock); .
- *
- * Returns pointer to "struct tomoyo_domain_info" if found, NULL otherwise.
+ * Returns true if found, false otherwise.
  */
-struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname)
+bool tomoyo_find_domain(const char *domainname, struct tomoyo_cookie *cookie)
 {
 	struct tomoyo_domain_info *domain;
 	struct tomoyo_path_info name;
 
+	cookie->u.domain = NULL;
 	name.name = domainname;
 	tomoyo_fill_path_info(&name);
+	/***** READER SECTION START *****/
+	down_read(&tomoyo_policy_lock);
 	list_for_each_entry(domain, &tomoyo_domain_list, list) {
-		if (!domain->is_deleted &&
-		    !tomoyo_pathcmp(&name, domain->domainname))
-			return domain;
+		if (domain->is_deleted ||
+		    tomoyo_pathcmp(&name, domain->domainname))
+			continue;
+		cookie->u.domain = domain;
+		break;
 	}
-	return NULL;
+	up_read(&tomoyo_policy_lock);
+	/***** READER SECTION END *****/
+	return cookie->u.domain != NULL;
 }
 
 /**
@@ -421,7 +430,7 @@ static int tomoyo_const_part_length(cons
  *
  * @ptr: Pointer to "struct tomoyo_path_info" to fill in.
  *
- * The caller sets "struct tomoyo_path_info"->name.
+ * The caller sets @ptr->name.
  */
 void tomoyo_fill_path_info(struct tomoyo_path_info *ptr)
 {
@@ -763,7 +772,7 @@ unsigned int tomoyo_check_flags(const st
  * @domain: Pointer to "struct tomoyo_domain_info".
  *
  * Returns true if domain policy violation warning should be printed to
- * console.
+ * console, false otherwise.
  */
 bool tomoyo_verbose_mode(const struct tomoyo_domain_info *domain)
 {
@@ -784,7 +793,8 @@ bool tomoyo_domain_quota_is_ok(struct to
 
 	if (!domain)
 		return true;
-	down_read(&tomoyo_domain_acl_info_list_lock);
+	/***** READER SECTION START *****/
+	down_read(&tomoyo_policy_lock);
 	list_for_each_entry(ptr, &domain->acl_info_list, list) {
 		if (ptr->type & TOMOYO_ACL_DELETED)
 			continue;
@@ -838,7 +848,13 @@ bool tomoyo_domain_quota_is_ok(struct to
 			break;
 		}
 	}
-	up_read(&tomoyo_domain_acl_info_list_lock);
+	up_read(&tomoyo_policy_lock);
+	/***** READER SECTION END *****/
+	/*
+	 * This is safe because domain is either
+	 * ((struct tomoyo_cookie *) current->cred->security)->u.domain or
+	 * ((struct tomoyo_cookie *) bprm->cred->security)->u.domain .
+	 */
 	if (count < tomoyo_check_flags(domain, TOMOYO_MAX_ACCEPT_ENTRY))
 		return true;
 	if (!domain->quota_warned) {
@@ -860,27 +876,27 @@ bool tomoyo_domain_quota_is_ok(struct to
 static struct tomoyo_profile *tomoyo_find_or_assign_new_profile(const unsigned
 								int profile)
 {
-	static DEFINE_MUTEX(lock);
-	struct tomoyo_profile *ptr = NULL;
+	struct tomoyo_profile *entry;
+	struct tomoyo_profile *ptr;
 	int i;
 
 	if (profile >= TOMOYO_MAX_PROFILES)
 		return NULL;
-	/***** EXCLUSIVE SECTION START *****/
-	mutex_lock(&lock);
+	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+	/***** WRITER SECTION START *****/
+	down_write(&tomoyo_policy_lock);
 	ptr = tomoyo_profile_ptr[profile];
-	if (ptr)
-		goto ok;
-	ptr = tomoyo_alloc_element(sizeof(*ptr));
-	if (!ptr)
-		goto ok;
-	for (i = 0; i < TOMOYO_MAX_CONTROL_INDEX; i++)
-		ptr->value[i] = tomoyo_control_array[i].current_value;
-	mb(); /* Avoid out-of-order execution. */
-	tomoyo_profile_ptr[profile] = ptr;
- ok:
-	mutex_unlock(&lock);
-	/***** EXCLUSIVE SECTION END *****/
+	if (!ptr && tomoyo_alloc_element(entry)) {
+		for (i = 0; i < TOMOYO_MAX_CONTROL_INDEX; i++)
+			entry->value[i] = tomoyo_control_array[i].current_value;
+		mb(); /* Avoid out-of-order execution. */
+		tomoyo_profile_ptr[profile] = entry;
+		ptr = entry;
+		entry = NULL;
+	}
+	up_write(&tomoyo_policy_lock);
+	/***** WRITER SECTION END *****/
+	kfree(entry);
 	return ptr;
 }
 
@@ -915,7 +931,16 @@ static int tomoyo_write_profile(struct t
 		return -EINVAL;
 	*cp = '\0';
 	if (!strcmp(data, "COMMENT")) {
-		profile->comment = tomoyo_save_name(cp + 1);
+		const struct tomoyo_path_info *new_comment
+			= tomoyo_get_name(cp + 1);
+		const struct tomoyo_path_info *old_comment;
+		/***** WRITER SECTION START *****/
+		down_write(&tomoyo_policy_lock);
+		old_comment = profile->comment;
+		profile->comment = new_comment;
+		up_write(&tomoyo_policy_lock);
+		/***** WRITER SECTION END *****/
+		tomoyo_put_name(old_comment);
 		return 0;
 	}
 	for (i = 0; i < TOMOYO_MAX_CONTROL_INDEX; i++) {
@@ -943,6 +968,7 @@ static int tomoyo_write_profile(struct t
 		} else if (value > tomoyo_control_array[i].max_value) {
 			value = tomoyo_control_array[i].max_value;
 		}
+		/* profile is not deleted. */
 		profile->value[i] = value;
 		return 0;
 	}
@@ -967,15 +993,22 @@ static int tomoyo_read_profile(struct to
 	     step++) {
 		const u8 index = step / total;
 		u8 type = step % total;
+		/* profile is not deleted. */
 		const struct tomoyo_profile *profile
 			= tomoyo_profile_ptr[index];
 		head->read_step = step;
 		if (!profile)
 			continue;
 		if (!type) { /* Print profile' comment tag. */
-			if (!tomoyo_io_printf(head, "%u-COMMENT=%s\n",
-					      index, profile->comment ?
-					      profile->comment->name : ""))
+			bool done;
+			/***** READER SECTION START *****/
+			down_read(&tomoyo_policy_lock);
+			done = tomoyo_io_printf(head, "%u-COMMENT=%s\n",
+						index, profile->comment ?
+						profile->comment->name : "");
+			up_read(&tomoyo_policy_lock);
+			/***** READER SECTION END *****/
+			if (!done)
 				break;
 			continue;
 		}
@@ -1009,18 +1042,8 @@ static int tomoyo_read_profile(struct to
 	return 0;
 }
 
-/* Structure for policy manager. */
-struct tomoyo_policy_manager_entry {
-	struct list_head list;
-	/* A path to program or a domainname. */
-	const struct tomoyo_path_info *manager;
-	bool is_domain;  /* True if manager is a domainname. */
-	bool is_deleted; /* True if this entry is deleted. */
-};
-
 /* The list for "struct tomoyo_policy_manager_entry". */
-static LIST_HEAD(tomoyo_policy_manager_list);
-static DECLARE_RWSEM(tomoyo_policy_manager_list_lock);
+LIST_HEAD(tomoyo_policy_manager_list);
 
 /**
  * tomoyo_update_manager_entry - Add a manager entry.
@@ -1033,10 +1056,10 @@ static DECLARE_RWSEM(tomoyo_policy_manag
 static int tomoyo_update_manager_entry(const char *manager,
 				       const bool is_delete)
 {
-	struct tomoyo_policy_manager_entry *new_entry;
+	struct tomoyo_policy_manager_entry *entry = NULL;
 	struct tomoyo_policy_manager_entry *ptr;
 	const struct tomoyo_path_info *saved_manager;
-	int error = -ENOMEM;
+	int error = is_delete ? -ENOENT : -ENOMEM;
 	bool is_domain = false;
 
 	if (tomoyo_is_domain_def(manager)) {
@@ -1047,32 +1070,32 @@ static int tomoyo_update_manager_entry(c
 		if (!tomoyo_is_correct_path(manager, 1, -1, -1, __func__))
 			return -EINVAL;
 	}
-	saved_manager = tomoyo_save_name(manager);
+	saved_manager = tomoyo_get_name(manager);
 	if (!saved_manager)
 		return -ENOMEM;
-	/***** EXCLUSIVE SECTION START *****/
-	down_write(&tomoyo_policy_manager_list_lock);
+	if (!is_delete)
+		entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+	/***** WRITER SECTION START *****/
+	down_write(&tomoyo_policy_lock);
 	list_for_each_entry(ptr, &tomoyo_policy_manager_list, list) {
 		if (ptr->manager != saved_manager)
 			continue;
 		ptr->is_deleted = is_delete;
 		error = 0;
-		goto out;
+		break;
 	}
-	if (is_delete) {
-		error = -ENOENT;
-		goto out;
+	if (!is_delete && error && tomoyo_alloc_element(entry)) {
+		entry->manager = saved_manager;
+		saved_manager = NULL;
+		entry->is_domain = is_domain;
+		list_add_tail(&entry->list, &tomoyo_policy_manager_list);
+		entry = NULL;
+		error = 0;
 	}
-	new_entry = tomoyo_alloc_element(sizeof(*new_entry));
-	if (!new_entry)
-		goto out;
-	new_entry->manager = saved_manager;
-	new_entry->is_domain = is_domain;
-	list_add_tail(&new_entry->list, &tomoyo_policy_manager_list);
-	error = 0;
- out:
-	up_write(&tomoyo_policy_manager_list_lock);
-	/***** EXCLUSIVE SECTION END *****/
+	up_write(&tomoyo_policy_lock);
+	/***** WRITER SECTION END *****/
+	tomoyo_put_name(saved_manager);
+	kfree(entry);
 	return error;
 }
 
@@ -1109,20 +1132,21 @@ static int tomoyo_read_manager_policy(st
 
 	if (head->read_eof)
 		return 0;
-	down_read(&tomoyo_policy_manager_list_lock);
-	list_for_each_cookie(pos, head->read_var2,
+	/***** READER SECTION START *****/
+	down_read(&tomoyo_policy_lock);
+	list_for_each_cookie(pos, head->read_cookie2.u.list,
 			     &tomoyo_policy_manager_list) {
 		struct tomoyo_policy_manager_entry *ptr;
 		ptr = list_entry(pos, struct tomoyo_policy_manager_entry,
 				 list);
 		if (ptr->is_deleted)
 			continue;
-		if (!tomoyo_io_printf(head, "%s\n", ptr->manager->name)) {
-			done = false;
+		done = tomoyo_io_printf(head, "%s\n", ptr->manager->name);
+		if (!done)
 			break;
-		}
 	}
-	up_read(&tomoyo_policy_manager_list_lock);
+	up_read(&tomoyo_policy_lock);
+	/***** READER SECTION END *****/
 	head->read_eof = done;
 	return 0;
 }
@@ -1145,7 +1169,8 @@ static bool tomoyo_is_policy_manager(voi
 		return true;
 	if (!tomoyo_manage_by_non_root && (task->cred->uid || task->cred->euid))
 		return false;
-	down_read(&tomoyo_policy_manager_list_lock);
+	/***** READER SECTION START *****/
+	down_read(&tomoyo_policy_lock);
 	list_for_each_entry(ptr, &tomoyo_policy_manager_list, list) {
 		if (!ptr->is_deleted && ptr->is_domain
 		    && !tomoyo_pathcmp(domainname, ptr->manager)) {
@@ -1153,13 +1178,15 @@ static bool tomoyo_is_policy_manager(voi
 			break;
 		}
 	}
-	up_read(&tomoyo_policy_manager_list_lock);
+	up_read(&tomoyo_policy_lock);
+	/***** READER SECTION END *****/
 	if (found)
 		return true;
 	exe = tomoyo_get_exe();
 	if (!exe)
 		return false;
-	down_read(&tomoyo_policy_manager_list_lock);
+	/***** READER SECTION START *****/
+	down_read(&tomoyo_policy_lock);
 	list_for_each_entry(ptr, &tomoyo_policy_manager_list, list) {
 		if (!ptr->is_deleted && !ptr->is_domain
 		    && !strcmp(exe, ptr->manager->name)) {
@@ -1167,7 +1194,8 @@ static bool tomoyo_is_policy_manager(voi
 			break;
 		}
 	}
-	up_read(&tomoyo_policy_manager_list_lock);
+	up_read(&tomoyo_policy_lock);
+	/***** READER SECTION END *****/
 	if (!found) { /* Reduce error messages. */
 		static pid_t last_pid;
 		const pid_t pid = current->pid;
@@ -1182,6 +1210,35 @@ static bool tomoyo_is_policy_manager(voi
 }
 
 /**
+ * tomoyo_delete_domain - Delete a domain.
+ *
+ * @domainname: The name of domain.
+ */
+static void tomoyo_delete_domain(char *domainname)
+{
+	struct tomoyo_domain_info *domain;
+	struct tomoyo_path_info name;
+
+	name.name = domainname;
+	tomoyo_fill_path_info(&name);
+	/***** WRITER SECTION START *****/
+	down_write(&tomoyo_policy_lock);
+	/* Is there an active domain? */
+	list_for_each_entry(domain, &tomoyo_domain_list, list) {
+		/* Never delete tomoyo_kernel_domain */
+		if (domain == &tomoyo_kernel_domain)
+			continue;
+		if (domain->is_deleted ||
+		    tomoyo_pathcmp(domain->domainname, &name))
+			continue;
+		domain->is_deleted = true;
+		break;
+	}
+	up_write(&tomoyo_policy_lock);
+	/***** WRITER SECTION END *****/
+}
+
+/**
  * tomoyo_is_select_one - Parse select command.
  *
  * @head: Pointer to "struct tomoyo_io_buffer".
@@ -1193,49 +1250,46 @@ static bool tomoyo_is_select_one(struct 
 				 const char *data)
 {
 	unsigned int pid;
-	struct tomoyo_domain_info *domain = NULL;
+	struct tomoyo_cookie *cookie = &head->write_cookie1;
 
 	if (sscanf(data, "pid=%u", &pid) == 1) {
 		struct task_struct *p;
+		cookie->u.domain = NULL;
+		/***** READER SECTION START *****/
+		down_read(&tomoyo_policy_lock);
 		/***** CRITICAL SECTION START *****/
-		read_lock(&tasklist_lock);
+		rcu_read_lock();
 		p = find_task_by_vpid(pid);
 		if (p)
-			domain = tomoyo_real_domain(p);
-		read_unlock(&tasklist_lock);
+			cookie->u.domain = tomoyo_real_domain(p);
+		rcu_read_unlock();
 		/***** CRITICAL SECTION END *****/
+		up_read(&tomoyo_policy_lock);
+		/***** READER SECTION END *****/
 	} else if (!strncmp(data, "domain=", 7)) {
-		if (tomoyo_is_domain_def(data + 7)) {
-			down_read(&tomoyo_domain_list_lock);
-			domain = tomoyo_find_domain(data + 7);
-			up_read(&tomoyo_domain_list_lock);
-		}
+		cookie->u.domain = NULL;
+		if (tomoyo_is_domain_def(data + 7))
+			tomoyo_find_domain(data + 7, cookie);
 	} else
 		return false;
-	head->write_var1 = domain;
 	/* Accessing read_buf is safe because head->io_sem is held. */
 	if (!head->read_buf)
 		return true; /* Do nothing if open(O_WRONLY). */
+	/***** READER SECTION START *****/
+	down_read(&tomoyo_policy_lock);
+	if (cookie->u.domain)
+		head->read_cookie1.u.list = cookie->u.domain->list.prev;
+	up_read(&tomoyo_policy_lock);
+	/***** READER SECTION END *****/
 	head->read_avail = 0;
 	tomoyo_io_printf(head, "# select %s\n", data);
 	head->read_single_domain = true;
-	head->read_eof = !domain;
-	if (domain) {
-		struct tomoyo_domain_info *d;
-		head->read_var1 = NULL;
-		down_read(&tomoyo_domain_list_lock);
-		list_for_each_entry(d, &tomoyo_domain_list, list) {
-			if (d == domain)
-				break;
-			head->read_var1 = &d->list;
-		}
-		up_read(&tomoyo_domain_list_lock);
-		head->read_var2 = NULL;
-		head->read_bit = 0;
-		head->read_step = 0;
-		if (domain->is_deleted)
-			tomoyo_io_printf(head, "# This is a deleted domain.\n");
-	}
+	head->read_eof = !cookie->u.domain;
+	head->read_cookie2.u.list = NULL;
+	head->read_bit = 0;
+	head->read_step = 0;
+	if (cookie->u.domain && cookie->u.domain->is_deleted)
+		tomoyo_io_printf(head, "# This is a deleted domain.\n");
 	return true;
 }
 
@@ -1249,7 +1303,7 @@ static bool tomoyo_is_select_one(struct 
 static int tomoyo_write_domain_policy(struct tomoyo_io_buffer *head)
 {
 	char *data = head->write_buf;
-	struct tomoyo_domain_info *domain = head->write_var1;
+	struct tomoyo_cookie *cookie = &head->write_cookie1;
 	bool is_delete = false;
 	bool is_select = false;
 	unsigned int profile;
@@ -1264,33 +1318,29 @@ static int tomoyo_write_domain_policy(st
 	if (!tomoyo_is_policy_manager())
 		return -EPERM;
 	if (tomoyo_is_domain_def(data)) {
-		domain = NULL;
+		cookie->u.domain = NULL;
 		if (is_delete)
 			tomoyo_delete_domain(data);
-		else if (is_select) {
-			down_read(&tomoyo_domain_list_lock);
-			domain = tomoyo_find_domain(data);
-			up_read(&tomoyo_domain_list_lock);
-		} else
-			domain = tomoyo_find_or_assign_new_domain(data, 0);
-		head->write_var1 = domain;
+		else if (is_select)
+			tomoyo_find_domain(data, cookie);
+		else
+			tomoyo_find_or_assign_new_domain(data, 0, cookie);
 		return 0;
 	}
-	if (!domain)
+	if (!cookie->u.domain)
 		return -EINVAL;
 
 	if (sscanf(data, TOMOYO_KEYWORD_USE_PROFILE "%u", &profile) == 1
 	    && profile < TOMOYO_MAX_PROFILES) {
 		if (tomoyo_profile_ptr[profile] || !tomoyo_policy_loaded)
-			domain->profile = (u8) profile;
+			cookie->u.domain->profile = (u8) profile;
 		return 0;
 	}
 	if (!strcmp(data, TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ)) {
-		tomoyo_set_domain_flag(domain, is_delete,
-			       TOMOYO_DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ);
+		cookie->u.domain->ignore_global_allow_read = !is_delete;
 		return 0;
 	}
-	return tomoyo_write_file_policy(data, domain, is_delete);
+	return tomoyo_write_file_policy(data, cookie->u.domain, is_delete);
 }
 
 /**
@@ -1427,8 +1477,10 @@ static int tomoyo_read_domain_policy(str
 		return 0;
 	if (head->read_step == 0)
 		head->read_step = 1;
-	down_read(&tomoyo_domain_list_lock);
-	list_for_each_cookie(dpos, head->read_var1, &tomoyo_domain_list) {
+	/***** READER SECTION START *****/
+	down_read(&tomoyo_policy_lock);
+	list_for_each_cookie(dpos, head->read_cookie1.u.list,
+			     &tomoyo_domain_list) {
 		struct tomoyo_domain_info *domain;
 		const char *quota_exceeded = "";
 		const char *transition_failed = "";
@@ -1441,51 +1493,47 @@ static int tomoyo_read_domain_policy(str
 		/* Print domainname and flags. */
 		if (domain->quota_warned)
 			quota_exceeded = "quota_exceeded\n";
-		if (domain->flags & TOMOYO_DOMAIN_FLAGS_TRANSITION_FAILED)
+		if (domain->domain_transition_failed)
 			transition_failed = "transition_failed\n";
-		if (domain->flags &
-		    TOMOYO_DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ)
+		if (domain->ignore_global_allow_read)
 			ignore_global_allow_read
 				= TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ "\n";
-		if (!tomoyo_io_printf(head,
-				      "%s\n" TOMOYO_KEYWORD_USE_PROFILE "%u\n"
-				      "%s%s%s\n", domain->domainname->name,
-				      domain->profile, quota_exceeded,
-				      transition_failed,
-				      ignore_global_allow_read)) {
-			done = false;
+		done = tomoyo_io_printf(head, "%s\n" TOMOYO_KEYWORD_USE_PROFILE
+					"%u\n%s%s%s\n",
+					domain->domainname->name,
+					domain->profile, quota_exceeded,
+					transition_failed,
+					ignore_global_allow_read);
+		if (!done)
 			break;
-		}
 		head->read_step = 2;
 acl_loop:
 		if (head->read_step == 3)
 			goto tail_mark;
 		/* Print ACL entries in the domain. */
-		down_read(&tomoyo_domain_acl_info_list_lock);
-		list_for_each_cookie(apos, head->read_var2,
-				      &domain->acl_info_list) {
+		list_for_each_cookie(apos, head->read_cookie2.u.list,
+				     &domain->acl_info_list) {
 			struct tomoyo_acl_info *ptr
 				= list_entry(apos, struct tomoyo_acl_info,
-					      list);
+					     list);
 			if (!tomoyo_print_entry(head, ptr)) {
 				done = false;
 				break;
 			}
 		}
-		up_read(&tomoyo_domain_acl_info_list_lock);
 		if (!done)
 			break;
 		head->read_step = 3;
 tail_mark:
-		if (!tomoyo_io_printf(head, "\n")) {
-			done = false;
+		done = tomoyo_io_printf(head, "\n");
+		if (!done)
 			break;
-		}
 		head->read_step = 1;
 		if (head->read_single_domain)
 			break;
 	}
-	up_read(&tomoyo_domain_list_lock);
+	up_read(&tomoyo_policy_lock);
+	/***** READER SECTION END *****/
 	head->read_eof = done;
 	return 0;
 }
@@ -1496,30 +1544,25 @@ tail_mark:
  * @head: Pointer to "struct tomoyo_io_buffer".
  *
  * Returns 0 on success, -EINVAL otherwise.
- *
- * This is equivalent to doing
- *
- *     ( echo "select " $domainname; echo "use_profile " $profile ) |
- *     /usr/lib/ccs/loadpolicy -d
  */
 static int tomoyo_write_domain_profile(struct tomoyo_io_buffer *head)
 {
 	char *data = head->write_buf;
 	char *cp = strchr(data, ' ');
-	struct tomoyo_domain_info *domain;
 	unsigned long profile;
+	struct tomoyo_cookie cookie;
 
 	if (!cp)
 		return -EINVAL;
 	*cp = '\0';
-	down_read(&tomoyo_domain_list_lock);
-	domain = tomoyo_find_domain(cp + 1);
-	up_read(&tomoyo_domain_list_lock);
-	if (strict_strtoul(data, 10, &profile))
+	if (strict_strtoul(data, 10, &profile) ||
+	    profile >= TOMOYO_MAX_PROFILES)
 		return -EINVAL;
-	if (domain && profile < TOMOYO_MAX_PROFILES
-	    && (tomoyo_profile_ptr[profile] || !tomoyo_policy_loaded))
-		domain->profile = (u8) profile;
+	tomoyo_add_cookie(&cookie, NULL);
+	if (tomoyo_find_domain(cp + 1, &cookie) &&
+	    (tomoyo_profile_ptr[profile] || !tomoyo_policy_loaded))
+		cookie.u.domain->profile = (u8) profile;
+	tomoyo_del_cookie(&cookie);
 	return 0;
 }
 
@@ -1529,13 +1572,6 @@ static int tomoyo_write_domain_profile(s
  * @head: Pointer to "struct tomoyo_io_buffer".
  *
  * Returns list of profile number and domainname pairs.
- *
- * This is equivalent to doing
- *
- *     grep -A 1 '^<kernel>' /sys/kernel/security/tomoyo/domain_policy |
- *     awk ' { if ( domainname == "" ) { if ( $1 == "<kernel>" )
- *     domainname = $0; } else if ( $1 == "use_profile" ) {
- *     print $2 " " domainname; domainname = ""; } } ; '
  */
 static int tomoyo_read_domain_profile(struct tomoyo_io_buffer *head)
 {
@@ -1544,19 +1580,21 @@ static int tomoyo_read_domain_profile(st
 
 	if (head->read_eof)
 		return 0;
-	down_read(&tomoyo_domain_list_lock);
-	list_for_each_cookie(pos, head->read_var1, &tomoyo_domain_list) {
+	/***** READER SECTION START *****/
+	down_read(&tomoyo_policy_lock);
+	list_for_each_cookie(pos, head->read_cookie1.u.list,
+			     &tomoyo_domain_list) {
 		struct tomoyo_domain_info *domain;
 		domain = list_entry(pos, struct tomoyo_domain_info, list);
 		if (domain->is_deleted)
 			continue;
-		if (!tomoyo_io_printf(head, "%u %s\n", domain->profile,
-				      domain->domainname->name)) {
-			done = false;
+		done = tomoyo_io_printf(head, "%u %s\n", domain->profile,
+					domain->domainname->name);
+		if (!done)
 			break;
-		}
 	}
-	up_read(&tomoyo_domain_list_lock);
+	up_read(&tomoyo_policy_lock);
+	/***** READER SECTION END *****/
 	head->read_eof = done;
 	return 0;
 }
@@ -1593,17 +1631,24 @@ static int tomoyo_read_pid(struct tomoyo
 	if (head->read_avail == 0 && !head->read_eof) {
 		const int pid = head->read_step;
 		struct task_struct *p;
-		struct tomoyo_domain_info *domain = NULL;
+		struct tomoyo_cookie cookie;
+		tomoyo_add_cookie(&cookie, NULL);
+		/***** READER SECTION START *****/
+		down_read(&tomoyo_policy_lock);
 		/***** CRITICAL SECTION START *****/
-		read_lock(&tasklist_lock);
+		rcu_read_lock();
 		p = find_task_by_vpid(pid);
 		if (p)
-			domain = tomoyo_real_domain(p);
-		read_unlock(&tasklist_lock);
+			cookie.u.domain = tomoyo_real_domain(p);
+		rcu_read_unlock();
 		/***** CRITICAL SECTION END *****/
-		if (domain)
-			tomoyo_io_printf(head, "%d %u %s", pid, domain->profile,
-					 domain->domainname->name);
+		up_read(&tomoyo_policy_lock);
+		/***** READER SECTION END *****/
+		if (cookie.u.domain)
+			tomoyo_io_printf(head, "%d %u %s", pid,
+					 cookie.u.domain->profile,
+					 cookie.u.domain->domainname->name);
+		tomoyo_del_cookie(&cookie);
 		head->read_eof = true;
 	}
 	return 0;
@@ -1655,43 +1700,43 @@ static int tomoyo_read_exception_policy(
 	if (!head->read_eof) {
 		switch (head->read_step) {
 		case 0:
-			head->read_var2 = NULL;
+			head->read_cookie2.u.list = NULL;
 			head->read_step = 1;
 		case 1:
 			if (!tomoyo_read_domain_keeper_policy(head))
 				break;
-			head->read_var2 = NULL;
+			head->read_cookie2.u.list = NULL;
 			head->read_step = 2;
 		case 2:
 			if (!tomoyo_read_globally_readable_policy(head))
 				break;
-			head->read_var2 = NULL;
+			head->read_cookie2.u.list = NULL;
 			head->read_step = 3;
 		case 3:
-			head->read_var2 = NULL;
+			head->read_cookie2.u.list = NULL;
 			head->read_step = 4;
 		case 4:
 			if (!tomoyo_read_domain_initializer_policy(head))
 				break;
-			head->read_var2 = NULL;
+			head->read_cookie2.u.list = NULL;
 			head->read_step = 5;
 		case 5:
 			if (!tomoyo_read_alias_policy(head))
 				break;
-			head->read_var2 = NULL;
+			head->read_cookie2.u.list = NULL;
 			head->read_step = 6;
 		case 6:
-			head->read_var2 = NULL;
+			head->read_cookie2.u.list = NULL;
 			head->read_step = 7;
 		case 7:
 			if (!tomoyo_read_file_pattern(head))
 				break;
-			head->read_var2 = NULL;
+			head->read_cookie2.u.list = NULL;
 			head->read_step = 8;
 		case 8:
 			if (!tomoyo_read_no_rewrite_policy(head))
 				break;
-			head->read_var2 = NULL;
+			head->read_cookie2.u.list = NULL;
 			head->read_step = 9;
 		case 9:
 			head->read_eof = true;
@@ -1736,13 +1781,13 @@ static bool tomoyo_policy_loader_exists(
  *
  * @filename: The program about to start.
  *
+ * Returns nothing.
+ *
  * This function checks whether @filename is /sbin/init , and if so
  * invoke /sbin/tomoyo-init and wait for the termination of /sbin/tomoyo-init
  * and then continues invocation of /sbin/init.
  * /sbin/tomoyo-init reads policy files in /etc/tomoyo/ directory and
  * writes to /sys/kernel/security/tomoyo/ interfaces.
- *
- * Returns nothing.
  */
 void tomoyo_load_policy(const char *filename)
 {
@@ -1778,7 +1823,8 @@ void tomoyo_load_policy(const char *file
 	tomoyo_policy_loaded = true;
 	{ /* Check all profiles currently assigned to domains are defined. */
 		struct tomoyo_domain_info *domain;
-		down_read(&tomoyo_domain_list_lock);
+		/***** READER SECTION START *****/
+		down_read(&tomoyo_policy_lock);
 		list_for_each_entry(domain, &tomoyo_domain_list, list) {
 			const u8 profile = domain->profile;
 			if (tomoyo_profile_ptr[profile])
@@ -1786,7 +1832,8 @@ void tomoyo_load_policy(const char *file
 			panic("Profile %u (used by '%s') not defined.\n",
 			      profile, domain->domainname->name);
 		}
-		up_read(&tomoyo_domain_list_lock);
+		up_read(&tomoyo_policy_lock);
+		/***** READER SECTION END *****/
 	}
 }
 
@@ -1919,6 +1966,9 @@ static int tomoyo_open_control(const u8 
 			return -ENOMEM;
 		}
 	}
+	tomoyo_add_cookie(&head->read_cookie1, NULL);
+	tomoyo_add_cookie(&head->read_cookie2, NULL);
+	tomoyo_add_cookie(&head->write_cookie1, NULL);
 	file->private_data = head;
 	/*
 	 * Call the handler now if the file is
@@ -2037,48 +2087,25 @@ static int tomoyo_write_control(struct f
 static int tomoyo_close_control(struct file *file)
 {
 	struct tomoyo_io_buffer *head = file->private_data;
+	const bool write_mode = head->write_buf != NULL;
 
 	/* Release memory used for policy I/O. */
 	tomoyo_free(head->read_buf);
 	head->read_buf = NULL;
 	tomoyo_free(head->write_buf);
 	head->write_buf = NULL;
+	tomoyo_del_cookie(&head->read_cookie1);
+	tomoyo_del_cookie(&head->read_cookie2);
+	tomoyo_del_cookie(&head->write_cookie1);
 	tomoyo_free(head);
 	head = NULL;
 	file->private_data = NULL;
+	if (write_mode)
+		tomoyo_run_garbage_collector();
 	return 0;
 }
 
 /**
- * tomoyo_alloc_acl_element - Allocate permanent memory for ACL entry.
- *
- * @acl_type:  Type of ACL entry.
- *
- * Returns pointer to the ACL entry on success, NULL otherwise.
- */
-void *tomoyo_alloc_acl_element(const u8 acl_type)
-{
-	int len;
-	struct tomoyo_acl_info *ptr;
-
-	switch (acl_type) {
-	case TOMOYO_TYPE_SINGLE_PATH_ACL:
-		len = sizeof(struct tomoyo_single_path_acl_record);
-		break;
-	case TOMOYO_TYPE_DOUBLE_PATH_ACL:
-		len = sizeof(struct tomoyo_double_path_acl_record);
-		break;
-	default:
-		return NULL;
-	}
-	ptr = tomoyo_alloc_element(len);
-	if (!ptr)
-		return NULL;
-	ptr->type = acl_type;
-	return ptr;
-}
-
-/**
  * tomoyo_open - open() for /sys/kernel/security/tomoyo/ interface.
  *
  * @inode: Pointer to "struct inode".
@@ -2171,9 +2198,10 @@ static void __init tomoyo_create_entry(c
 static int __init tomoyo_initerface_init(void)
 {
 	struct dentry *tomoyo_dir;
+	struct tomoyo_cookie *cookie = current_cred()->security;
 
 	/* Don't create securityfs entries unless registered. */
-	if (current_cred()->security != &tomoyo_kernel_domain)
+	if (!cookie || cookie->u.domain != &tomoyo_kernel_domain)
 		return 0;
 
 	tomoyo_dir = securityfs_create_dir("tomoyo", NULL);
--- security-testing-2.6.git.orig/security/tomoyo/common.h
+++ security-testing-2.6.git/security/tomoyo/common.h
@@ -26,6 +26,18 @@
 struct dentry;
 struct vfsmount;
 
+struct tomoyo_domain_info;
+struct tomoyo_path_info;
+struct tomoyo_cookie {
+	struct list_head list;
+	union {
+		const void *ptr;
+		struct list_head *list;
+		struct tomoyo_domain_info *domain;
+		const struct tomoyo_path_info *path;
+	} u;
+};
+
 /* Temporary buffer for holding pathnames. */
 struct tomoyo_page_buffer {
 	char buffer[4096];
@@ -90,23 +102,20 @@ struct tomoyo_domain_info {
 	u8 profile;        /* Profile number to use. */
 	bool is_deleted;   /* Delete flag.           */
 	bool quota_warned; /* Quota warnning flag.   */
-	/* DOMAIN_FLAGS_*. Use tomoyo_set_domain_flag() to modify. */
-	u8 flags;
+	/* Ignore "allow_read" directive in exception policy. */
+	bool ignore_global_allow_read;
+	/*
+	 * This domain was unable to create a new domain at
+	 * tomoyo_find_next_domain() because the name of the domain to be
+	 * created was too long or it could not allocate memory.
+	 * More than one process continued execve() without domain transition.
+	 */
+	bool domain_transition_failed;
 };
 
 /* Profile number is an integer between 0 and 255. */
 #define TOMOYO_MAX_PROFILES 256
 
-/* Ignore "allow_read" directive in exception policy. */
-#define TOMOYO_DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ 1
-/*
- * This domain was unable to create a new domain at tomoyo_find_next_domain()
- * because the name of the domain to be created was too long or
- * it could not allocate memory.
- * More than one process continued execve() without domain transition.
- */
-#define TOMOYO_DOMAIN_FLAGS_TRANSITION_FAILED        2
-
 /*
  * Structure for "allow_read/write", "allow_execute", "allow_read",
  * "allow_write", "allow_create", "allow_unlink", "allow_mkdir", "allow_rmdir",
@@ -160,11 +169,11 @@ struct tomoyo_io_buffer {
 	/* Exclusive lock for this structure.   */
 	struct mutex io_sem;
 	/* The position currently reading from. */
-	struct list_head *read_var1;
+	struct tomoyo_cookie read_cookie1;
 	/* Extra variables for reading.         */
-	struct list_head *read_var2;
+	struct tomoyo_cookie read_cookie2;
 	/* The position currently writing to.   */
-	struct tomoyo_domain_info *write_var1;
+	struct tomoyo_cookie write_cookie1;
 	/* The step for reading.                */
 	int read_step;
 	/* Buffer for reading.                  */
@@ -187,6 +196,66 @@ struct tomoyo_io_buffer {
 	int writebuf_size;
 };
 
+/* Structure for policy manager. */
+struct tomoyo_policy_manager_entry {
+	struct list_head list;
+	/* A path to program or a domainname. */
+	const struct tomoyo_path_info *manager;
+	bool is_domain;  /* True if manager is a domainname. */
+	bool is_deleted; /* True if this entry is deleted. */
+};
+
+/* Structure for "initialize_domain" and "no_initialize_domain" keyword. */
+struct tomoyo_domain_initializer_entry {
+	struct list_head list;
+	const struct tomoyo_path_info *domainname;    /* This may be NULL */
+	const struct tomoyo_path_info *program;
+	bool is_deleted;
+	bool is_not;       /* True if this entry is "no_initialize_domain".  */
+	/* True if the domainname is tomoyo_get_last_name(). */
+	bool is_last_name;
+};
+
+/* Structure for "keep_domain" and "no_keep_domain" keyword. */
+struct tomoyo_domain_keeper_entry {
+	struct list_head list;
+	const struct tomoyo_path_info *domainname;
+	const struct tomoyo_path_info *program;       /* This may be NULL */
+	bool is_deleted;
+	bool is_not;       /* True if this entry is "no_keep_domain".        */
+	/* True if the domainname is tomoyo_get_last_name(). */
+	bool is_last_name;
+};
+
+/* Structure for "alias" keyword. */
+struct tomoyo_alias_entry {
+	struct list_head list;
+	const struct tomoyo_path_info *original_name;
+	const struct tomoyo_path_info *aliased_name;
+	bool is_deleted;
+};
+
+/* Structure for "allow_read" keyword. */
+struct tomoyo_globally_readable_file_entry {
+	struct list_head list;
+	const struct tomoyo_path_info *filename;
+	bool is_deleted;
+};
+
+/* Structure for "file_pattern" keyword. */
+struct tomoyo_pattern_entry {
+	struct list_head list;
+	const struct tomoyo_path_info *pattern;
+	bool is_deleted;
+};
+
+/* Structure for "deny_rewrite" keyword. */
+struct tomoyo_no_rewrite_entry {
+	struct list_head list;
+	const struct tomoyo_path_info *pattern;
+	bool is_deleted;
+};
+
 /* Check whether the domain has too many ACL entries to hold. */
 bool tomoyo_domain_quota_is_ok(struct tomoyo_domain_info * const domain);
 /* Transactional sprintf() for policy dump. */
@@ -229,8 +298,6 @@ const char *tomoyo_get_last_name(const s
 const char *tomoyo_get_msg(const bool is_enforce);
 /* Convert single path operation to operation name. */
 const char *tomoyo_sp2keyword(const u8 operation);
-/* Delete a domain. */
-int tomoyo_delete_domain(char *data);
 /* Create "alias" entry in exception policy. */
 int tomoyo_write_alias_policy(char *data, const bool is_delete);
 /*
@@ -258,23 +325,24 @@ int tomoyo_write_no_rewrite_policy(char 
 /* Create "file_pattern" entry in exception policy. */
 int tomoyo_write_pattern_policy(char *data, const bool is_delete);
 /* Find a domain by the given name. */
-struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname);
+bool tomoyo_find_domain(const char *domainname, struct tomoyo_cookie *cookie);
 /* Find or create a domain by the given name. */
-struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
-							    domainname,
-							    const u8 profile);
+bool tomoyo_find_or_assign_new_domain(const char *domainname, const u8 profile,
+				      struct tomoyo_cookie *cookie);
 /* Check mode for specified functionality. */
 unsigned int tomoyo_check_flags(const struct tomoyo_domain_info *domain,
 				const u8 index);
-/* Allocate memory for structures. */
-void *tomoyo_alloc_acl_element(const u8 acl_type);
 /* Fill in "struct tomoyo_path_info" members. */
 void tomoyo_fill_path_info(struct tomoyo_path_info *ptr);
 /* Run policy loader when /sbin/init starts. */
 void tomoyo_load_policy(const char *filename);
-/* Change "struct tomoyo_domain_info"->flags. */
-void tomoyo_set_domain_flag(struct tomoyo_domain_info *domain,
-			    const bool is_delete, const u8 flags);
+/* Cleanup deleted entries. */
+void tomoyo_run_garbage_collector(void);
+
+static inline struct tomoyo_domain_info *tomoyo_domain(void)
+{
+	return ((struct tomoyo_cookie *) current_cred()->security)->u.domain;
+}
 
 /* strcmp() for "struct tomoyo_path_info" structure. */
 static inline bool tomoyo_pathcmp(const struct tomoyo_path_info *a,
@@ -319,12 +387,18 @@ static inline bool tomoyo_is_invalid(con
 	return c && (c <= ' ' || c >= 127);
 }
 
+/* Lock for modifying policy. */
+extern struct rw_semaphore tomoyo_policy_lock;
+
 /* The list for "struct tomoyo_domain_info". */
 extern struct list_head tomoyo_domain_list;
-extern struct rw_semaphore tomoyo_domain_list_lock;
-
-/* Lock for domain->acl_info_list. */
-extern struct rw_semaphore tomoyo_domain_acl_info_list_lock;
+extern struct list_head tomoyo_policy_manager_list;
+extern struct list_head tomoyo_globally_readable_list;
+extern struct list_head tomoyo_pattern_list;
+extern struct list_head tomoyo_no_rewrite_list;
+extern struct list_head tomoyo_domain_initializer_list;
+extern struct list_head tomoyo_domain_keeper_list;
+extern struct list_head tomoyo_alias_list;
 
 /* Has /sbin/init started? */
 extern bool tomoyo_policy_loaded;
--- security-testing-2.6.git.orig/security/tomoyo/domain.c
+++ security-testing-2.6.git/security/tomoyo/domain.c
@@ -21,61 +21,7 @@ struct tomoyo_domain_info tomoyo_kernel_
 
 /* The list for "struct tomoyo_domain_info". */
 LIST_HEAD(tomoyo_domain_list);
-DECLARE_RWSEM(tomoyo_domain_list_lock);
-
-/* Structure for "initialize_domain" and "no_initialize_domain" keyword. */
-struct tomoyo_domain_initializer_entry {
-	struct list_head list;
-	const struct tomoyo_path_info *domainname;    /* This may be NULL */
-	const struct tomoyo_path_info *program;
-	bool is_deleted;
-	bool is_not;       /* True if this entry is "no_initialize_domain".  */
-	/* True if the domainname is tomoyo_get_last_name(). */
-	bool is_last_name;
-};
-
-/* Structure for "keep_domain" and "no_keep_domain" keyword. */
-struct tomoyo_domain_keeper_entry {
-	struct list_head list;
-	const struct tomoyo_path_info *domainname;
-	const struct tomoyo_path_info *program;       /* This may be NULL */
-	bool is_deleted;
-	bool is_not;       /* True if this entry is "no_keep_domain".        */
-	/* True if the domainname is tomoyo_get_last_name(). */
-	bool is_last_name;
-};
-
-/* Structure for "alias" keyword. */
-struct tomoyo_alias_entry {
-	struct list_head list;
-	const struct tomoyo_path_info *original_name;
-	const struct tomoyo_path_info *aliased_name;
-	bool is_deleted;
-};
-
-/**
- * tomoyo_set_domain_flag - Set or clear domain's attribute flags.
- *
- * @domain:    Pointer to "struct tomoyo_domain_info".
- * @is_delete: True if it is a delete request.
- * @flags:     Flags to set or clear.
- *
- * Returns nothing.
- */
-void tomoyo_set_domain_flag(struct tomoyo_domain_info *domain,
-			    const bool is_delete, const u8 flags)
-{
-	/* We need to serialize because this is bitfield operation. */
-	static DEFINE_SPINLOCK(lock);
-	/***** CRITICAL SECTION START *****/
-	spin_lock(&lock);
-	if (!is_delete)
-		domain->flags |= flags;
-	else
-		domain->flags &= ~flags;
-	spin_unlock(&lock);
-	/***** CRITICAL SECTION END *****/
-}
+DECLARE_RWSEM(tomoyo_policy_lock);
 
 /**
  * tomoyo_get_last_name - Get last component of a domainname.
@@ -83,6 +29,8 @@ void tomoyo_set_domain_flag(struct tomoy
  * @domain: Pointer to "struct tomoyo_domain_info".
  *
  * Returns the last component of the domainname.
+ *
+ * @domain must be either current domain or saved in the cookie list.
  */
 const char *tomoyo_get_last_name(const struct tomoyo_domain_info *domain)
 {
@@ -95,8 +43,7 @@ const char *tomoyo_get_last_name(const s
 }
 
 /* The list for "struct tomoyo_domain_initializer_entry". */
-static LIST_HEAD(tomoyo_domain_initializer_list);
-static DECLARE_RWSEM(tomoyo_domain_initializer_list_lock);
+LIST_HEAD(tomoyo_domain_initializer_list);
 
 /**
  * tomoyo_update_domain_initializer_entry - Update "struct tomoyo_domain_initializer_entry" list.
@@ -113,11 +60,11 @@ static int tomoyo_update_domain_initiali
 						  const bool is_not,
 						  const bool is_delete)
 {
-	struct tomoyo_domain_initializer_entry *new_entry;
+	struct tomoyo_domain_initializer_entry *entry = NULL;
 	struct tomoyo_domain_initializer_entry *ptr;
 	const struct tomoyo_path_info *saved_program;
 	const struct tomoyo_path_info *saved_domainname = NULL;
-	int error = -ENOMEM;
+	int error = is_delete ? -ENOENT : -ENOMEM;
 	bool is_last_name = false;
 
 	if (!tomoyo_is_correct_path(program, 1, -1, -1, __func__))
@@ -128,15 +75,17 @@ static int tomoyo_update_domain_initiali
 			is_last_name = true;
 		else if (!tomoyo_is_correct_domain(domainname, __func__))
 			return -EINVAL;
-		saved_domainname = tomoyo_save_name(domainname);
+		saved_domainname = tomoyo_get_name(domainname);
 		if (!saved_domainname)
 			return -ENOMEM;
 	}
-	saved_program = tomoyo_save_name(program);
+	saved_program = tomoyo_get_name(program);
 	if (!saved_program)
-		return -ENOMEM;
-	/***** EXCLUSIVE SECTION START *****/
-	down_write(&tomoyo_domain_initializer_list_lock);
+		goto out;
+	if (!is_delete)
+		entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+	/***** WRITER SECTION START *****/
+	down_write(&tomoyo_policy_lock);
 	list_for_each_entry(ptr, &tomoyo_domain_initializer_list, list) {
 		if (ptr->is_not != is_not ||
 		    ptr->domainname != saved_domainname ||
@@ -144,24 +93,25 @@ static int tomoyo_update_domain_initiali
 			continue;
 		ptr->is_deleted = is_delete;
 		error = 0;
-		goto out;
+		break;
 	}
-	if (is_delete) {
-		error = -ENOENT;
-		goto out;
+	if (!is_delete && error && tomoyo_alloc_element(entry)) {
+		entry->domainname = saved_domainname;
+		saved_domainname = NULL;
+		entry->program = saved_program;
+		saved_program = NULL;
+		entry->is_not = is_not;
+		entry->is_last_name = is_last_name;
+		list_add_tail(&entry->list, &tomoyo_domain_initializer_list);
+		entry = NULL;
+		error = 0;
 	}
-	new_entry = tomoyo_alloc_element(sizeof(*new_entry));
-	if (!new_entry)
-		goto out;
-	new_entry->domainname = saved_domainname;
-	new_entry->program = saved_program;
-	new_entry->is_not = is_not;
-	new_entry->is_last_name = is_last_name;
-	list_add_tail(&new_entry->list, &tomoyo_domain_initializer_list);
-	error = 0;
+	up_write(&tomoyo_policy_lock);
+	/***** WRITER SECTION END *****/
  out:
-	up_write(&tomoyo_domain_initializer_list_lock);
-	/***** EXCLUSIVE SECTION END *****/
+	tomoyo_put_name(saved_domainname);
+	tomoyo_put_name(saved_program);
+	kfree(entry);
 	return error;
 }
 
@@ -177,15 +127,16 @@ bool tomoyo_read_domain_initializer_poli
 	struct list_head *pos;
 	bool done = true;
 
-	down_read(&tomoyo_domain_initializer_list_lock);
-	list_for_each_cookie(pos, head->read_var2,
+	/***** READER SECTION START *****/
+	down_read(&tomoyo_policy_lock);
+	list_for_each_cookie(pos, head->read_cookie2.u.list,
 			     &tomoyo_domain_initializer_list) {
 		const char *no;
 		const char *from = "";
 		const char *domain = "";
 		struct tomoyo_domain_initializer_entry *ptr;
 		ptr = list_entry(pos, struct tomoyo_domain_initializer_entry,
-				  list);
+				 list);
 		if (ptr->is_deleted)
 			continue;
 		no = ptr->is_not ? "no_" : "";
@@ -193,15 +144,15 @@ bool tomoyo_read_domain_initializer_poli
 			from = " from ";
 			domain = ptr->domainname->name;
 		}
-		if (!tomoyo_io_printf(head,
-				      "%s" TOMOYO_KEYWORD_INITIALIZE_DOMAIN
-				      "%s%s%s\n", no, ptr->program->name, from,
-				      domain)) {
-			done = false;
+		done = tomoyo_io_printf(head,
+					"%s" TOMOYO_KEYWORD_INITIALIZE_DOMAIN
+					"%s%s%s\n", no, ptr->program->name,
+					from, domain);
+		if (!done)
 			break;
-		}
 	}
-	up_read(&tomoyo_domain_initializer_list_lock);
+	up_read(&tomoyo_policy_lock);
+	/***** READER SECTION END *****/
 	return done;
 }
 
@@ -248,7 +199,8 @@ static bool tomoyo_is_domain_initializer
 	struct tomoyo_domain_initializer_entry *ptr;
 	bool flag = false;
 
-	down_read(&tomoyo_domain_initializer_list_lock);
+	/***** READER SECTION START *****/
+	down_read(&tomoyo_policy_lock);
 	list_for_each_entry(ptr,  &tomoyo_domain_initializer_list, list) {
 		if (ptr->is_deleted)
 			continue;
@@ -269,13 +221,13 @@ static bool tomoyo_is_domain_initializer
 		}
 		flag = true;
 	}
-	up_read(&tomoyo_domain_initializer_list_lock);
+	up_read(&tomoyo_policy_lock);
+	/***** READER SECTION END *****/
 	return flag;
 }
 
 /* The list for "struct tomoyo_domain_keeper_entry". */
-static LIST_HEAD(tomoyo_domain_keeper_list);
-static DECLARE_RWSEM(tomoyo_domain_keeper_list_lock);
+LIST_HEAD(tomoyo_domain_keeper_list);
 
 /**
  * tomoyo_update_domain_keeper_entry - Update "struct tomoyo_domain_keeper_entry" list.
@@ -292,12 +244,12 @@ static int tomoyo_update_domain_keeper_e
 					     const bool is_not,
 					     const bool is_delete)
 {
-	struct tomoyo_domain_keeper_entry *new_entry;
+	struct tomoyo_domain_keeper_entry *entry = NULL;
 	struct tomoyo_domain_keeper_entry *ptr;
 	const struct tomoyo_path_info *saved_domainname;
 	const struct tomoyo_path_info *saved_program = NULL;
 	static DEFINE_MUTEX(lock);
-	int error = -ENOMEM;
+	int error = is_delete ? -ENOENT : -ENOMEM;
 	bool is_last_name = false;
 
 	if (!tomoyo_is_domain_def(domainname) &&
@@ -308,15 +260,17 @@ static int tomoyo_update_domain_keeper_e
 	if (program) {
 		if (!tomoyo_is_correct_path(program, 1, -1, -1, __func__))
 			return -EINVAL;
-		saved_program = tomoyo_save_name(program);
+		saved_program = tomoyo_get_name(program);
 		if (!saved_program)
 			return -ENOMEM;
 	}
-	saved_domainname = tomoyo_save_name(domainname);
+	saved_domainname = tomoyo_get_name(domainname);
 	if (!saved_domainname)
-		return -ENOMEM;
-	/***** EXCLUSIVE SECTION START *****/
-	down_write(&tomoyo_domain_keeper_list_lock);
+		goto out;
+	if (!is_delete)
+		entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+	/***** WRITER SECTION START *****/
+	down_write(&tomoyo_policy_lock);
 	list_for_each_entry(ptr, &tomoyo_domain_keeper_list, list) {
 		if (ptr->is_not != is_not ||
 		    ptr->domainname != saved_domainname ||
@@ -324,24 +278,25 @@ static int tomoyo_update_domain_keeper_e
 			continue;
 		ptr->is_deleted = is_delete;
 		error = 0;
-		goto out;
+		break;
 	}
-	if (is_delete) {
-		error = -ENOENT;
-		goto out;
+	if (!is_delete && error && tomoyo_alloc_element(entry)) {
+		entry->domainname = saved_domainname;
+		saved_domainname = NULL;
+		entry->program = saved_program;
+		saved_program = NULL;
+		entry->is_not = is_not;
+		entry->is_last_name = is_last_name;
+		list_add_tail(&entry->list, &tomoyo_domain_keeper_list);
+		entry = NULL;
+		error = 0;
 	}
-	new_entry = tomoyo_alloc_element(sizeof(*new_entry));
-	if (!new_entry)
-		goto out;
-	new_entry->domainname = saved_domainname;
-	new_entry->program = saved_program;
-	new_entry->is_not = is_not;
-	new_entry->is_last_name = is_last_name;
-	list_add_tail(&new_entry->list, &tomoyo_domain_keeper_list);
-	error = 0;
+	up_write(&tomoyo_policy_lock);
+	/***** WRITER SECTION END *****/
  out:
-	up_write(&tomoyo_domain_keeper_list_lock);
-	/***** EXCLUSIVE SECTION END *****/
+	tomoyo_put_name(saved_domainname);
+	tomoyo_put_name(saved_program);
+	kfree(entry);
 	return error;
 }
 
@@ -378,8 +333,9 @@ bool tomoyo_read_domain_keeper_policy(st
 	struct list_head *pos;
 	bool done = true;
 
-	down_read(&tomoyo_domain_keeper_list_lock);
-	list_for_each_cookie(pos, head->read_var2,
+	/***** READER SECTION START *****/
+	down_read(&tomoyo_policy_lock);
+	list_for_each_cookie(pos, head->read_cookie2.u.list,
 			     &tomoyo_domain_keeper_list) {
 		struct tomoyo_domain_keeper_entry *ptr;
 		const char *no;
@@ -394,15 +350,15 @@ bool tomoyo_read_domain_keeper_policy(st
 			from = " from ";
 			program = ptr->program->name;
 		}
-		if (!tomoyo_io_printf(head,
-				      "%s" TOMOYO_KEYWORD_KEEP_DOMAIN
-				      "%s%s%s\n", no, program, from,
-				      ptr->domainname->name)) {
-			done = false;
+		done = tomoyo_io_printf(head,
+					"%s" TOMOYO_KEYWORD_KEEP_DOMAIN
+					"%s%s%s\n", no, program, from,
+					ptr->domainname->name);
+		if (!done)
 			break;
-		}
 	}
-	up_read(&tomoyo_domain_keeper_list_lock);
+	up_read(&tomoyo_policy_lock);
+	/***** READER SECTION END *****/
 	return done;
 }
 
@@ -423,7 +379,8 @@ static bool tomoyo_is_domain_keeper(cons
 	struct tomoyo_domain_keeper_entry *ptr;
 	bool flag = false;
 
-	down_read(&tomoyo_domain_keeper_list_lock);
+	/***** READER SECTION START *****/
+	down_read(&tomoyo_policy_lock);
 	list_for_each_entry(ptr, &tomoyo_domain_keeper_list, list) {
 		if (ptr->is_deleted)
 			continue;
@@ -442,13 +399,13 @@ static bool tomoyo_is_domain_keeper(cons
 		}
 		flag = true;
 	}
-	up_read(&tomoyo_domain_keeper_list_lock);
+	up_read(&tomoyo_policy_lock);
+	/***** READER SECTION END *****/
 	return flag;
 }
 
 /* The list for "struct tomoyo_alias_entry". */
-static LIST_HEAD(tomoyo_alias_list);
-static DECLARE_RWSEM(tomoyo_alias_list_lock);
+LIST_HEAD(tomoyo_alias_list);
 
 /**
  * tomoyo_update_alias_entry - Update "struct tomoyo_alias_entry" list.
@@ -463,43 +420,46 @@ static int tomoyo_update_alias_entry(con
 				     const char *aliased_name,
 				     const bool is_delete)
 {
-	struct tomoyo_alias_entry *new_entry;
+	struct tomoyo_alias_entry *entry = NULL;
 	struct tomoyo_alias_entry *ptr;
 	const struct tomoyo_path_info *saved_original_name;
 	const struct tomoyo_path_info *saved_aliased_name;
-	int error = -ENOMEM;
+	int error = is_delete ? -ENOENT : -ENOMEM;
 
 	if (!tomoyo_is_correct_path(original_name, 1, -1, -1, __func__) ||
 	    !tomoyo_is_correct_path(aliased_name, 1, -1, -1, __func__))
 		return -EINVAL; /* No patterns allowed. */
-	saved_original_name = tomoyo_save_name(original_name);
-	saved_aliased_name = tomoyo_save_name(aliased_name);
+	saved_original_name = tomoyo_get_name(original_name);
+	saved_aliased_name = tomoyo_get_name(aliased_name);
 	if (!saved_original_name || !saved_aliased_name)
-		return -ENOMEM;
-	/***** EXCLUSIVE SECTION START *****/
-	down_write(&tomoyo_alias_list_lock);
+		goto out;
+	if (!is_delete)
+		entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+	/***** WRITER SECTION START *****/
+	down_write(&tomoyo_policy_lock);
 	list_for_each_entry(ptr, &tomoyo_alias_list, list) {
 		if (ptr->original_name != saved_original_name ||
 		    ptr->aliased_name != saved_aliased_name)
 			continue;
 		ptr->is_deleted = is_delete;
 		error = 0;
-		goto out;
+		break;
 	}
-	if (is_delete) {
-		error = -ENOENT;
-		goto out;
+	if (!is_delete && error && tomoyo_alloc_element(entry)) {
+		entry->original_name = saved_original_name;
+		saved_original_name = NULL;
+		entry->aliased_name = saved_aliased_name;
+		saved_aliased_name = NULL;
+		list_add_tail(&entry->list, &tomoyo_alias_list);
+		entry = NULL;
+		error = 0;
 	}
-	new_entry = tomoyo_alloc_element(sizeof(*new_entry));
-	if (!new_entry)
-		goto out;
-	new_entry->original_name = saved_original_name;
-	new_entry->aliased_name = saved_aliased_name;
-	list_add_tail(&new_entry->list, &tomoyo_alias_list);
-	error = 0;
+	up_write(&tomoyo_policy_lock);
+	/***** WRITER SECTION END *****/
  out:
-	up_write(&tomoyo_alias_list_lock);
-	/***** EXCLUSIVE SECTION END *****/
+	tomoyo_put_name(saved_original_name);
+	tomoyo_put_name(saved_aliased_name);
+	kfree(entry);
 	return error;
 }
 
@@ -515,21 +475,23 @@ bool tomoyo_read_alias_policy(struct tom
 	struct list_head *pos;
 	bool done = true;
 
-	down_read(&tomoyo_alias_list_lock);
-	list_for_each_cookie(pos, head->read_var2, &tomoyo_alias_list) {
+	/***** READER SECTION START *****/
+	down_read(&tomoyo_policy_lock);
+	list_for_each_cookie(pos, head->read_cookie2.u.list,
+			     &tomoyo_alias_list) {
 		struct tomoyo_alias_entry *ptr;
 
 		ptr = list_entry(pos, struct tomoyo_alias_entry, list);
 		if (ptr->is_deleted)
 			continue;
-		if (!tomoyo_io_printf(head, TOMOYO_KEYWORD_ALIAS "%s %s\n",
-				      ptr->original_name->name,
-				      ptr->aliased_name->name)) {
-			done = false;
+		done = tomoyo_io_printf(head, TOMOYO_KEYWORD_ALIAS "%s %s\n",
+					ptr->original_name->name,
+					ptr->aliased_name->name);
+		if (!done)
 			break;
-		}
 	}
-	up_read(&tomoyo_alias_list_lock);
+	up_read(&tomoyo_policy_lock);
+	/***** READER SECTION END *****/
 	return done;
 }
 
@@ -551,120 +513,64 @@ int tomoyo_write_alias_policy(char *data
 	return tomoyo_update_alias_entry(data, cp, is_delete);
 }
 
-/* Domain create/delete handler. */
-
-/**
- * tomoyo_delete_domain - Delete a domain.
- *
- * @domainname: The name of domain.
- *
- * Returns 0.
- */
-int tomoyo_delete_domain(char *domainname)
-{
-	struct tomoyo_domain_info *domain;
-	struct tomoyo_path_info name;
-
-	name.name = domainname;
-	tomoyo_fill_path_info(&name);
-	/***** EXCLUSIVE SECTION START *****/
-	down_write(&tomoyo_domain_list_lock);
-	/* Is there an active domain? */
-	list_for_each_entry(domain, &tomoyo_domain_list, list) {
-		/* Never delete tomoyo_kernel_domain */
-		if (domain == &tomoyo_kernel_domain)
-			continue;
-		if (domain->is_deleted ||
-		    tomoyo_pathcmp(domain->domainname, &name))
-			continue;
-		domain->is_deleted = true;
-		break;
-	}
-	up_write(&tomoyo_domain_list_lock);
-	/***** EXCLUSIVE SECTION END *****/
-	return 0;
-}
+/* Domain create handler. */
 
 /**
  * tomoyo_find_or_assign_new_domain - Create a domain.
  *
  * @domainname: The name of domain.
  * @profile:    Profile number to assign if the domain was newly created.
+ * @cookie:     Pointer to "struct tomoyo_cookie".
  *
- * Returns pointer to "struct tomoyo_domain_info" on success, NULL otherwise.
+ * Returns true on success, false otherwise.
  */
-struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
-							    domainname,
-							    const u8 profile)
+bool tomoyo_find_or_assign_new_domain(const char *domainname, const u8 profile,
+				      struct tomoyo_cookie *cookie)
 {
-	struct tomoyo_domain_info *domain = NULL;
+	struct tomoyo_domain_info *entry;
+	struct tomoyo_domain_info *domain;
 	const struct tomoyo_path_info *saved_domainname;
 
-	/***** EXCLUSIVE SECTION START *****/
-	down_write(&tomoyo_domain_list_lock);
-	domain = tomoyo_find_domain(domainname);
-	if (domain)
-		goto out;
+	cookie->u.domain = NULL;
 	if (!tomoyo_is_correct_domain(domainname, __func__))
-		goto out;
-	saved_domainname = tomoyo_save_name(domainname);
+		return false;
+	saved_domainname = tomoyo_get_name(domainname);
 	if (!saved_domainname)
-		goto out;
-	/* Can I reuse memory of deleted domain? */
+		return false;
+	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+	/***** WRITER SECTION START *****/
+	down_write(&tomoyo_policy_lock);
 	list_for_each_entry(domain, &tomoyo_domain_list, list) {
-		struct task_struct *p;
-		struct tomoyo_acl_info *ptr;
-		bool flag;
-		if (!domain->is_deleted ||
-		    domain->domainname != saved_domainname)
-			continue;
-		flag = false;
-		/***** CRITICAL SECTION START *****/
-		read_lock(&tasklist_lock);
-		for_each_process(p) {
-			if (tomoyo_real_domain(p) != domain)
-				continue;
-			flag = true;
-			break;
-		}
-		read_unlock(&tasklist_lock);
-		/***** CRITICAL SECTION END *****/
-		if (flag)
+		if (domain->is_deleted ||
+		    tomoyo_pathcmp(saved_domainname, domain->domainname))
 			continue;
-		list_for_each_entry(ptr, &domain->acl_info_list, list) {
-			ptr->type |= TOMOYO_ACL_DELETED;
-		}
-		tomoyo_set_domain_flag(domain, true, domain->flags);
-		domain->profile = profile;
-		domain->quota_warned = false;
-		mb(); /* Avoid out-of-order execution. */
-		domain->is_deleted = false;
-		goto out;
-	}
-	/* No memory reusable. Create using new memory. */
-	domain = tomoyo_alloc_element(sizeof(*domain));
-	if (domain) {
-		INIT_LIST_HEAD(&domain->acl_info_list);
-		domain->domainname = saved_domainname;
-		domain->profile = profile;
-		list_add_tail(&domain->list, &tomoyo_domain_list);
+		cookie->u.domain = domain;
+		break;
 	}
- out:
-	up_write(&tomoyo_domain_list_lock);
-	/***** EXCLUSIVE SECTION END *****/
-	return domain;
+	if (!cookie->u.domain && tomoyo_alloc_element(entry)) {
+		INIT_LIST_HEAD(&entry->acl_info_list);
+		entry->domainname = saved_domainname;
+		saved_domainname = NULL;
+		entry->profile = profile;
+		list_add_tail(&entry->list, &tomoyo_domain_list);
+		cookie->u.domain = entry;
+		entry = NULL;
+	}
+	up_write(&tomoyo_policy_lock);
+	/***** WRITER SECTION END *****/
+	tomoyo_put_name(saved_domainname);
+	kfree(entry);
+	return cookie->u.domain != NULL;
 }
 
 /**
  * tomoyo_find_next_domain - Find a domain.
  *
- * @bprm:           Pointer to "struct linux_binprm".
- * @next_domain:    Pointer to pointer to "struct tomoyo_domain_info".
+ * @bprm: Pointer to "struct linux_binprm".
  *
  * Returns 0 on success, negative value otherwise.
  */
-int tomoyo_find_next_domain(struct linux_binprm *bprm,
-			    struct tomoyo_domain_info **next_domain)
+int tomoyo_find_next_domain(struct linux_binprm *bprm)
 {
 	/*
 	 * This function assumes that the size of buffer returned by
@@ -672,7 +578,6 @@ int tomoyo_find_next_domain(struct linux
 	 */
 	struct tomoyo_page_buffer *tmp = tomoyo_alloc(sizeof(*tmp));
 	struct tomoyo_domain_info *old_domain = tomoyo_domain();
-	struct tomoyo_domain_info *domain = NULL;
 	const char *old_domain_name = old_domain->domainname->name;
 	const char *original_name = bprm->filename;
 	char *new_domain_name = NULL;
@@ -685,6 +590,8 @@ int tomoyo_find_next_domain(struct linux
 	struct tomoyo_path_info s; /* symlink name */
 	struct tomoyo_path_info l; /* last name */
 	static bool initialized;
+	struct tomoyo_cookie *cookie = bprm->cred->security;
+	bool found = false;
 
 	if (!tmp)
 		goto out;
@@ -723,7 +630,8 @@ int tomoyo_find_next_domain(struct linux
 	if (tomoyo_pathcmp(&r, &s)) {
 		struct tomoyo_alias_entry *ptr;
 		/* Is this program allowed to be called via symbolic links? */
-		down_read(&tomoyo_alias_list_lock);
+		/***** READER SECTION START *****/
+		down_read(&tomoyo_policy_lock);
 		list_for_each_entry(ptr, &tomoyo_alias_list, list) {
 			if (ptr->is_deleted ||
 			    tomoyo_pathcmp(&r, ptr->original_name) ||
@@ -735,7 +643,8 @@ int tomoyo_find_next_domain(struct linux
 			tomoyo_fill_path_info(&r);
 			break;
 		}
-		up_read(&tomoyo_alias_list_lock);
+		up_read(&tomoyo_policy_lock);
+		/***** READER SECTION END *****/
 	}
 
 	/* Check execute permission. */
@@ -755,40 +664,38 @@ int tomoyo_find_next_domain(struct linux
 		 * /sbin/init. But transit from kernel domain if executing
 		 * initializers because they might start before /sbin/init.
 		 */
-		domain = old_domain;
+		found = true;
+		/* This is safe because old_domain is already in cookie list. */
+		cookie->u.domain = old_domain;
 	} else if (tomoyo_is_domain_keeper(old_domain->domainname, &r, &l)) {
 		/* Keep current domain. */
-		domain = old_domain;
+		found = true;
+		/* This is safe because old_domain is already in cookie list. */
+		cookie->u.domain = old_domain;
 	} else {
 		/* Normal domain transition. */
 		snprintf(new_domain_name, TOMOYO_MAX_PATHNAME_LEN + 1,
 			 "%s %s", old_domain_name, real_program_name);
 	}
-	if (domain || strlen(new_domain_name) >= TOMOYO_MAX_PATHNAME_LEN)
-		goto done;
-	down_read(&tomoyo_domain_list_lock);
-	domain = tomoyo_find_domain(new_domain_name);
-	up_read(&tomoyo_domain_list_lock);
-	if (domain)
-		goto done;
-	if (is_enforce)
+	if (found || strlen(new_domain_name) >= TOMOYO_MAX_PATHNAME_LEN)
 		goto done;
-	domain = tomoyo_find_or_assign_new_domain(new_domain_name,
-						  old_domain->profile);
+	found = tomoyo_find_domain(new_domain_name, cookie);
+	if (!found && !is_enforce)
+		found = tomoyo_find_or_assign_new_domain(new_domain_name,
+							 old_domain->profile,
+							 cookie);
  done:
-	if (domain)
+	if (found)
 		goto out;
 	printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n",
 	       new_domain_name);
 	if (is_enforce)
 		retval = -EPERM;
 	else
-		tomoyo_set_domain_flag(old_domain, false,
-				       TOMOYO_DOMAIN_FLAGS_TRANSITION_FAILED);
+		old_domain->domain_transition_failed = true;
  out:
 	tomoyo_free(real_program_name);
 	tomoyo_free(symlink_program_name);
-	*next_domain = domain ? domain : old_domain;
 	tomoyo_free(tmp);
 	return retval;
 }
--- security-testing-2.6.git.orig/security/tomoyo/file.c
+++ security-testing-2.6.git/security/tomoyo/file.c
@@ -14,27 +14,6 @@
 #include "realpath.h"
 #define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE])
 
-/* Structure for "allow_read" keyword. */
-struct tomoyo_globally_readable_file_entry {
-	struct list_head list;
-	const struct tomoyo_path_info *filename;
-	bool is_deleted;
-};
-
-/* Structure for "file_pattern" keyword. */
-struct tomoyo_pattern_entry {
-	struct list_head list;
-	const struct tomoyo_path_info *pattern;
-	bool is_deleted;
-};
-
-/* Structure for "deny_rewrite" keyword. */
-struct tomoyo_no_rewrite_entry {
-	struct list_head list;
-	const struct tomoyo_path_info *pattern;
-	bool is_deleted;
-};
-
 /* Keyword array for single path operations. */
 static const char *tomoyo_sp_keyword[TOMOYO_MAX_SINGLE_PATH_OPERATION] = {
 	[TOMOYO_TYPE_READ_WRITE_ACL] = "read/write",
@@ -130,9 +109,6 @@ static struct tomoyo_path_info *tomoyo_g
 	return NULL;
 }
 
-/* Lock for domain->acl_info_list. */
-DECLARE_RWSEM(tomoyo_domain_acl_info_list_lock);
-
 static int tomoyo_update_double_path_acl(const u8 type, const char *filename1,
 					 const char *filename2,
 					 struct tomoyo_domain_info *
@@ -142,8 +118,7 @@ static int tomoyo_update_single_path_acl
 					 const domain, const bool is_delete);
 
 /* The list for "struct tomoyo_globally_readable_file_entry". */
-static LIST_HEAD(tomoyo_globally_readable_list);
-static DECLARE_RWSEM(tomoyo_globally_readable_list_lock);
+LIST_HEAD(tomoyo_globally_readable_list);
 
 /**
  * tomoyo_update_globally_readable_entry - Update "struct tomoyo_globally_readable_file_entry" list.
@@ -156,38 +131,38 @@ static DECLARE_RWSEM(tomoyo_globally_rea
 static int tomoyo_update_globally_readable_entry(const char *filename,
 						 const bool is_delete)
 {
-	struct tomoyo_globally_readable_file_entry *new_entry;
+	struct tomoyo_globally_readable_file_entry *entry = NULL;
 	struct tomoyo_globally_readable_file_entry *ptr;
 	const struct tomoyo_path_info *saved_filename;
-	int error = -ENOMEM;
+	int error = is_delete ? -ENOENT : -ENOMEM;
 
 	if (!tomoyo_is_correct_path(filename, 1, 0, -1, __func__))
 		return -EINVAL;
-	saved_filename = tomoyo_save_name(filename);
+	saved_filename = tomoyo_get_name(filename);
 	if (!saved_filename)
 		return -ENOMEM;
-	/***** EXCLUSIVE SECTION START *****/
-	down_write(&tomoyo_globally_readable_list_lock);
+	if (!is_delete)
+		entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+	/***** WRITER SECTION START *****/
+	down_write(&tomoyo_policy_lock);
 	list_for_each_entry(ptr, &tomoyo_globally_readable_list, list) {
 		if (ptr->filename != saved_filename)
 			continue;
 		ptr->is_deleted = is_delete;
 		error = 0;
-		goto out;
+		break;
 	}
-	if (is_delete) {
-		error = -ENOENT;
-		goto out;
+	if (!is_delete && error && tomoyo_alloc_element(entry)) {
+		entry->filename = saved_filename;
+		saved_filename = NULL;
+		list_add_tail(&entry->list, &tomoyo_globally_readable_list);
+		entry = NULL;
+		error = 0;
 	}
-	new_entry = tomoyo_alloc_element(sizeof(*new_entry));
-	if (!new_entry)
-		goto out;
-	new_entry->filename = saved_filename;
-	list_add_tail(&new_entry->list, &tomoyo_globally_readable_list);
-	error = 0;
- out:
-	up_write(&tomoyo_globally_readable_list_lock);
-	/***** EXCLUSIVE SECTION END *****/
+	up_write(&tomoyo_policy_lock);
+	/***** WRITER SECTION END *****/
+	tomoyo_put_name(saved_filename);
+	kfree(entry);
 	return error;
 }
 
@@ -203,7 +178,9 @@ static bool tomoyo_is_globally_readable_
 {
 	struct tomoyo_globally_readable_file_entry *ptr;
 	bool found = false;
-	down_read(&tomoyo_globally_readable_list_lock);
+
+	/***** READER SECTION START *****/
+	down_read(&tomoyo_policy_lock);
 	list_for_each_entry(ptr, &tomoyo_globally_readable_list, list) {
 		if (!ptr->is_deleted &&
 		    tomoyo_path_matches_pattern(filename, ptr->filename)) {
@@ -211,7 +188,8 @@ static bool tomoyo_is_globally_readable_
 			break;
 		}
 	}
-	up_read(&tomoyo_globally_readable_list_lock);
+	up_read(&tomoyo_policy_lock);
+	/***** READER SECTION END *****/
 	return found;
 }
 
@@ -240,8 +218,9 @@ bool tomoyo_read_globally_readable_polic
 	struct list_head *pos;
 	bool done = true;
 
-	down_read(&tomoyo_globally_readable_list_lock);
-	list_for_each_cookie(pos, head->read_var2,
+	/***** READER SECTION START *****/
+	down_read(&tomoyo_policy_lock);
+	list_for_each_cookie(pos, head->read_cookie2.u.list,
 			     &tomoyo_globally_readable_list) {
 		struct tomoyo_globally_readable_file_entry *ptr;
 		ptr = list_entry(pos,
@@ -249,19 +228,18 @@ bool tomoyo_read_globally_readable_polic
 				 list);
 		if (ptr->is_deleted)
 			continue;
-		if (!tomoyo_io_printf(head, TOMOYO_KEYWORD_ALLOW_READ "%s\n",
-				      ptr->filename->name)) {
-			done = false;
+		done = tomoyo_io_printf(head, TOMOYO_KEYWORD_ALLOW_READ "%s\n",
+					ptr->filename->name);
+		if (!done)
 			break;
-		}
 	}
-	up_read(&tomoyo_globally_readable_list_lock);
+	up_read(&tomoyo_policy_lock);
+	/***** READER SECTION END *****/
 	return done;
 }
 
 /* The list for "struct tomoyo_pattern_entry". */
-static LIST_HEAD(tomoyo_pattern_list);
-static DECLARE_RWSEM(tomoyo_pattern_list_lock);
+LIST_HEAD(tomoyo_pattern_list);
 
 /**
  * tomoyo_update_file_pattern_entry - Update "struct tomoyo_pattern_entry" list.
@@ -274,55 +252,55 @@ static DECLARE_RWSEM(tomoyo_pattern_list
 static int tomoyo_update_file_pattern_entry(const char *pattern,
 					    const bool is_delete)
 {
-	struct tomoyo_pattern_entry *new_entry;
+	struct tomoyo_pattern_entry *entry = NULL;
 	struct tomoyo_pattern_entry *ptr;
 	const struct tomoyo_path_info *saved_pattern;
-	int error = -ENOMEM;
+	int error = is_delete ? -ENOENT : -ENOMEM;
 
 	if (!tomoyo_is_correct_path(pattern, 0, 1, 0, __func__))
 		return -EINVAL;
-	saved_pattern = tomoyo_save_name(pattern);
+	saved_pattern = tomoyo_get_name(pattern);
 	if (!saved_pattern)
 		return -ENOMEM;
-	/***** EXCLUSIVE SECTION START *****/
-	down_write(&tomoyo_pattern_list_lock);
+	if (!is_delete)
+		entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+	/***** WRITER SECTION START *****/
+	down_write(&tomoyo_policy_lock);
 	list_for_each_entry(ptr, &tomoyo_pattern_list, list) {
 		if (saved_pattern != ptr->pattern)
 			continue;
 		ptr->is_deleted = is_delete;
 		error = 0;
-		goto out;
+		break;
 	}
-	if (is_delete) {
-		error = -ENOENT;
-		goto out;
+	if (!is_delete && error && tomoyo_alloc_element(entry)) {
+		entry->pattern = saved_pattern;
+		saved_pattern = NULL;
+		list_add_tail(&entry->list, &tomoyo_pattern_list);
+		entry = NULL;
+		error = 0;
 	}
-	new_entry = tomoyo_alloc_element(sizeof(*new_entry));
-	if (!new_entry)
-		goto out;
-	new_entry->pattern = saved_pattern;
-	list_add_tail(&new_entry->list, &tomoyo_pattern_list);
-	error = 0;
- out:
-	up_write(&tomoyo_pattern_list_lock);
-	/***** EXCLUSIVE SECTION END *****/
+	up_write(&tomoyo_policy_lock);
+	/***** WRITER SECTION END *****/
+	tomoyo_put_name(saved_pattern);
+	kfree(entry);
 	return error;
 }
 
 /**
  * tomoyo_get_file_pattern - Get patterned pathname.
  *
- * @filename: The filename to find patterned pathname.
- *
- * Returns pointer to pathname pattern if matched, @filename otherwise.
+ * @cookie: Pointer to "struct tomoyo_cookie".
  */
-static const struct tomoyo_path_info *
-tomoyo_get_file_pattern(const struct tomoyo_path_info *filename)
+static void tomoyo_get_file_pattern(struct tomoyo_cookie *cookie)
 {
 	struct tomoyo_pattern_entry *ptr;
 	const struct tomoyo_path_info *pattern = NULL;
+	/* This is safe because cookie->u.path is not in policy. */
+	const struct tomoyo_path_info *filename = cookie->u.path;
 
-	down_read(&tomoyo_pattern_list_lock);
+	/***** READER SECTION START *****/
+	down_read(&tomoyo_policy_lock);
 	list_for_each_entry(ptr, &tomoyo_pattern_list, list) {
 		if (ptr->is_deleted)
 			continue;
@@ -336,10 +314,10 @@ tomoyo_get_file_pattern(const struct tom
 			break;
 		}
 	}
-	up_read(&tomoyo_pattern_list_lock);
 	if (pattern)
-		filename = pattern;
-	return filename;
+		cookie->u.path = pattern;
+	up_read(&tomoyo_policy_lock);
+	/***** READER SECTION END *****/
 }
 
 /**
@@ -367,25 +345,26 @@ bool tomoyo_read_file_pattern(struct tom
 	struct list_head *pos;
 	bool done = true;
 
-	down_read(&tomoyo_pattern_list_lock);
-	list_for_each_cookie(pos, head->read_var2, &tomoyo_pattern_list) {
+	/***** READER SECTION START *****/
+	down_read(&tomoyo_policy_lock);
+	list_for_each_cookie(pos, head->read_cookie2.u.list,
+			     &tomoyo_pattern_list) {
 		struct tomoyo_pattern_entry *ptr;
 		ptr = list_entry(pos, struct tomoyo_pattern_entry, list);
 		if (ptr->is_deleted)
 			continue;
-		if (!tomoyo_io_printf(head, TOMOYO_KEYWORD_FILE_PATTERN "%s\n",
-				      ptr->pattern->name)) {
-			done = false;
+		done = tomoyo_io_printf(head, TOMOYO_KEYWORD_FILE_PATTERN
+					"%s\n", ptr->pattern->name);
+		if (!done)
 			break;
-		}
 	}
-	up_read(&tomoyo_pattern_list_lock);
+	up_read(&tomoyo_policy_lock);
+	/***** READER SECTION END *****/
 	return done;
 }
 
 /* The list for "struct tomoyo_no_rewrite_entry". */
-static LIST_HEAD(tomoyo_no_rewrite_list);
-static DECLARE_RWSEM(tomoyo_no_rewrite_list_lock);
+LIST_HEAD(tomoyo_no_rewrite_list);
 
 /**
  * tomoyo_update_no_rewrite_entry - Update "struct tomoyo_no_rewrite_entry" list.
@@ -398,37 +377,38 @@ static DECLARE_RWSEM(tomoyo_no_rewrite_l
 static int tomoyo_update_no_rewrite_entry(const char *pattern,
 					  const bool is_delete)
 {
-	struct tomoyo_no_rewrite_entry *new_entry, *ptr;
+	struct tomoyo_no_rewrite_entry *entry = NULL;
+	struct tomoyo_no_rewrite_entry *ptr;
 	const struct tomoyo_path_info *saved_pattern;
-	int error = -ENOMEM;
+	int error = is_delete ? -ENOENT : -ENOMEM;
 
 	if (!tomoyo_is_correct_path(pattern, 0, 0, 0, __func__))
 		return -EINVAL;
-	saved_pattern = tomoyo_save_name(pattern);
+	saved_pattern = tomoyo_get_name(pattern);
 	if (!saved_pattern)
 		return -ENOMEM;
-	/***** EXCLUSIVE SECTION START *****/
-	down_write(&tomoyo_no_rewrite_list_lock);
+	if (!is_delete)
+		entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+	/***** WRITER SECTION START *****/
+	down_write(&tomoyo_policy_lock);
 	list_for_each_entry(ptr, &tomoyo_no_rewrite_list, list) {
 		if (ptr->pattern != saved_pattern)
 			continue;
 		ptr->is_deleted = is_delete;
 		error = 0;
-		goto out;
+		break;
 	}
-	if (is_delete) {
-		error = -ENOENT;
-		goto out;
+	if (!is_delete && error && tomoyo_alloc_element(entry)) {
+		entry->pattern = saved_pattern;
+		saved_pattern = NULL;
+		list_add_tail(&entry->list, &tomoyo_no_rewrite_list);
+		entry = NULL;
+		error = 0;
 	}
-	new_entry = tomoyo_alloc_element(sizeof(*new_entry));
-	if (!new_entry)
-		goto out;
-	new_entry->pattern = saved_pattern;
-	list_add_tail(&new_entry->list, &tomoyo_no_rewrite_list);
-	error = 0;
- out:
-	up_write(&tomoyo_no_rewrite_list_lock);
-	/***** EXCLUSIVE SECTION END *****/
+	up_write(&tomoyo_policy_lock);
+	/***** WRITER SECTION END *****/
+	tomoyo_put_name(saved_pattern);
+	kfree(entry);
 	return error;
 }
 
@@ -445,7 +425,8 @@ static bool tomoyo_is_no_rewrite_file(co
 	struct tomoyo_no_rewrite_entry *ptr;
 	bool found = false;
 
-	down_read(&tomoyo_no_rewrite_list_lock);
+	/***** READER SECTION START *****/
+	down_read(&tomoyo_policy_lock);
 	list_for_each_entry(ptr, &tomoyo_no_rewrite_list, list) {
 		if (ptr->is_deleted)
 			continue;
@@ -454,7 +435,8 @@ static bool tomoyo_is_no_rewrite_file(co
 		found = true;
 		break;
 	}
-	up_read(&tomoyo_no_rewrite_list_lock);
+	up_read(&tomoyo_policy_lock);
+	/***** READER SECTION END *****/
 	return found;
 }
 
@@ -483,19 +465,21 @@ bool tomoyo_read_no_rewrite_policy(struc
 	struct list_head *pos;
 	bool done = true;
 
-	down_read(&tomoyo_no_rewrite_list_lock);
-	list_for_each_cookie(pos, head->read_var2, &tomoyo_no_rewrite_list) {
+	/***** READER SECTION START *****/
+	down_read(&tomoyo_policy_lock);
+	list_for_each_cookie(pos, head->read_cookie2.u.list,
+			     &tomoyo_no_rewrite_list) {
 		struct tomoyo_no_rewrite_entry *ptr;
 		ptr = list_entry(pos, struct tomoyo_no_rewrite_entry, list);
 		if (ptr->is_deleted)
 			continue;
-		if (!tomoyo_io_printf(head, TOMOYO_KEYWORD_DENY_REWRITE "%s\n",
-				      ptr->pattern->name)) {
-			done = false;
+		done = tomoyo_io_printf(head, TOMOYO_KEYWORD_DENY_REWRITE
+					"%s\n", ptr->pattern->name);
+		if (!done)
 			break;
-		}
 	}
-	up_read(&tomoyo_no_rewrite_list_lock);
+	up_read(&tomoyo_policy_lock);
+	/***** READER SECTION END *****/
 	return done;
 }
 
@@ -561,7 +545,8 @@ static int tomoyo_check_single_path_acl2
 	struct tomoyo_acl_info *ptr;
 	int error = -EPERM;
 
-	down_read(&tomoyo_domain_acl_info_list_lock);
+	/***** READER SECTION START *****/
+	down_read(&tomoyo_policy_lock);
 	list_for_each_entry(ptr, &domain->acl_info_list, list) {
 		struct tomoyo_single_path_acl_record *acl;
 		if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL)
@@ -580,7 +565,8 @@ static int tomoyo_check_single_path_acl2
 		error = 0;
 		break;
 	}
-	up_read(&tomoyo_domain_acl_info_list_lock);
+	up_read(&tomoyo_policy_lock);
+	/***** READER SECTION END *****/
 	return error;
 }
 
@@ -638,8 +624,7 @@ static int tomoyo_check_file_perm2(struc
 	if (!filename)
 		return 0;
 	error = tomoyo_check_file_acl(domain, filename, perm);
-	if (error && perm == 4 &&
-	    (domain->flags & TOMOYO_DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ) == 0
+	if (error && perm == 4 && !domain->ignore_global_allow_read
 	    && tomoyo_is_globally_readable_file(filename))
 		error = 0;
 	if (perm == 6)
@@ -662,10 +647,17 @@ static int tomoyo_check_file_perm2(struc
 		return error;
 	if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) {
 		/* Don't use patterns for execute permission. */
-		const struct tomoyo_path_info *patterned_file = (perm != 1) ?
-			tomoyo_get_file_pattern(filename) : filename;
-		tomoyo_update_file_acl(patterned_file->name, perm,
-				       domain, false);
+		if (perm == 1) {
+			tomoyo_update_file_acl(filename->name, perm, domain,
+					       false);
+		} else {
+			struct tomoyo_cookie cookie;
+			tomoyo_add_cookie(&cookie, filename);
+			tomoyo_get_file_pattern(&cookie);
+			tomoyo_update_file_acl(cookie.u.path->name, perm,
+					       domain, false);
+			tomoyo_del_cookie(&cookie);
+		}
 	}
 	return 0;
 }
@@ -734,22 +726,24 @@ static int tomoyo_update_single_path_acl
 		(1 << TOMOYO_TYPE_READ_ACL) | (1 << TOMOYO_TYPE_WRITE_ACL);
 	const struct tomoyo_path_info *saved_filename;
 	struct tomoyo_acl_info *ptr;
-	struct tomoyo_single_path_acl_record *acl;
-	int error = -ENOMEM;
+	struct tomoyo_single_path_acl_record *entry = NULL;
+	int error = is_delete ? -ENOENT : -ENOMEM;
 	const u16 perm = 1 << type;
 
 	if (!domain)
 		return -EINVAL;
 	if (!tomoyo_is_correct_path(filename, 0, 0, 0, __func__))
 		return -EINVAL;
-	saved_filename = tomoyo_save_name(filename);
+	saved_filename = tomoyo_get_name(filename);
 	if (!saved_filename)
 		return -ENOMEM;
-	/***** EXCLUSIVE SECTION START *****/
-	down_write(&tomoyo_domain_acl_info_list_lock);
 	if (is_delete)
 		goto delete;
+	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+	/***** WRITER SECTION START *****/
+	down_write(&tomoyo_policy_lock);
 	list_for_each_entry(ptr, &domain->acl_info_list, list) {
+		struct tomoyo_single_path_acl_record *acl;
 		if (tomoyo_acl_type1(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL)
 			continue;
 		acl = container_of(ptr, struct tomoyo_single_path_acl_record,
@@ -766,22 +760,27 @@ static int tomoyo_update_single_path_acl
 			acl->perm |= rw_mask;
 		ptr->type &= ~TOMOYO_ACL_DELETED;
 		error = 0;
-		goto out;
+		break;
 	}
-	/* Not found. Append it to the tail. */
-	acl = tomoyo_alloc_acl_element(TOMOYO_TYPE_SINGLE_PATH_ACL);
-	if (!acl)
-		goto out;
-	acl->perm = perm;
-	if (perm == (1 << TOMOYO_TYPE_READ_WRITE_ACL))
-		acl->perm |= rw_mask;
-	acl->filename = saved_filename;
-	list_add_tail(&acl->head.list, &domain->acl_info_list);
-	error = 0;
+	if (error && tomoyo_alloc_element(entry)) {
+		entry->head.type = TOMOYO_TYPE_SINGLE_PATH_ACL;
+		entry->perm = perm;
+		if (perm == (1 << TOMOYO_TYPE_READ_WRITE_ACL))
+			entry->perm |= rw_mask;
+		entry->filename = saved_filename;
+		saved_filename = NULL;
+		list_add_tail(&entry->head.list, &domain->acl_info_list);
+		entry = NULL;
+		error = 0;
+	}
+	up_write(&tomoyo_policy_lock);
+	/***** WRITER SECTION END *****/
 	goto out;
  delete:
-	error = -ENOENT;
+	/***** WRITER SECTION START *****/
+	down_write(&tomoyo_policy_lock);
 	list_for_each_entry(ptr, &domain->acl_info_list, list) {
+		struct tomoyo_single_path_acl_record *acl;
 		if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL)
 			continue;
 		acl = container_of(ptr, struct tomoyo_single_path_acl_record,
@@ -798,9 +797,11 @@ static int tomoyo_update_single_path_acl
 		error = 0;
 		break;
 	}
+	up_write(&tomoyo_policy_lock);
+	/***** WRITER SECTION END *****/
  out:
-	up_write(&tomoyo_domain_acl_info_list_lock);
-	/***** EXCLUSIVE SECTION END *****/
+	tomoyo_put_name(saved_filename);
+	kfree(entry);
 	return error;
 }
 
@@ -823,8 +824,8 @@ static int tomoyo_update_double_path_acl
 	const struct tomoyo_path_info *saved_filename1;
 	const struct tomoyo_path_info *saved_filename2;
 	struct tomoyo_acl_info *ptr;
-	struct tomoyo_double_path_acl_record *acl;
-	int error = -ENOMEM;
+	struct tomoyo_double_path_acl_record *entry = NULL;
+	int error = is_delete ? -ENOENT : -ENOMEM;
 	const u8 perm = 1 << type;
 
 	if (!domain)
@@ -832,15 +833,17 @@ static int tomoyo_update_double_path_acl
 	if (!tomoyo_is_correct_path(filename1, 0, 0, 0, __func__) ||
 	    !tomoyo_is_correct_path(filename2, 0, 0, 0, __func__))
 		return -EINVAL;
-	saved_filename1 = tomoyo_save_name(filename1);
-	saved_filename2 = tomoyo_save_name(filename2);
+	saved_filename1 = tomoyo_get_name(filename1);
+	saved_filename2 = tomoyo_get_name(filename2);
 	if (!saved_filename1 || !saved_filename2)
-		return -ENOMEM;
-	/***** EXCLUSIVE SECTION START *****/
-	down_write(&tomoyo_domain_acl_info_list_lock);
+		goto out;
 	if (is_delete)
 		goto delete;
+	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+	/***** WRITER SECTION START *****/
+	down_write(&tomoyo_policy_lock);
 	list_for_each_entry(ptr, &domain->acl_info_list, list) {
+		struct tomoyo_double_path_acl_record *acl;
 		if (tomoyo_acl_type1(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL)
 			continue;
 		acl = container_of(ptr, struct tomoyo_double_path_acl_record,
@@ -854,21 +857,27 @@ static int tomoyo_update_double_path_acl
 		acl->perm |= perm;
 		ptr->type &= ~TOMOYO_ACL_DELETED;
 		error = 0;
-		goto out;
+		break;
 	}
-	/* Not found. Append it to the tail. */
-	acl = tomoyo_alloc_acl_element(TOMOYO_TYPE_DOUBLE_PATH_ACL);
-	if (!acl)
-		goto out;
-	acl->perm = perm;
-	acl->filename1 = saved_filename1;
-	acl->filename2 = saved_filename2;
-	list_add_tail(&acl->head.list, &domain->acl_info_list);
-	error = 0;
+	if (error && tomoyo_alloc_element(entry)) {
+		entry->head.type = TOMOYO_TYPE_DOUBLE_PATH_ACL;
+		entry->perm = perm;
+		entry->filename1 = saved_filename1;
+		saved_filename1 = NULL;
+		entry->filename2 = saved_filename2;
+		saved_filename2 = NULL;
+		list_add_tail(&entry->head.list, &domain->acl_info_list);
+		entry = NULL;
+		error = 0;
+	}
+	up_write(&tomoyo_policy_lock);
+	/***** WRITER SECTION END *****/
 	goto out;
  delete:
-	error = -ENOENT;
+	/***** WRITER SECTION START *****/
+	down_write(&tomoyo_policy_lock);
 	list_for_each_entry(ptr, &domain->acl_info_list, list) {
+		struct tomoyo_double_path_acl_record *acl;
 		if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL)
 			continue;
 		acl = container_of(ptr, struct tomoyo_double_path_acl_record,
@@ -882,9 +891,12 @@ static int tomoyo_update_double_path_acl
 		error = 0;
 		break;
 	}
+	up_write(&tomoyo_policy_lock);
+	/***** WRITER SECTION END *****/
  out:
-	up_write(&tomoyo_domain_acl_info_list_lock);
-	/***** EXCLUSIVE SECTION END *****/
+	tomoyo_put_name(saved_filename1);
+	tomoyo_put_name(saved_filename2);
+	kfree(entry);
 	return error;
 }
 
@@ -929,7 +941,8 @@ static int tomoyo_check_double_path_acl(
 
 	if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE))
 		return 0;
-	down_read(&tomoyo_domain_acl_info_list_lock);
+	/***** READER SECTION START *****/
+	down_read(&tomoyo_policy_lock);
 	list_for_each_entry(ptr, &domain->acl_info_list, list) {
 		struct tomoyo_double_path_acl_record *acl;
 		if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL)
@@ -945,7 +958,8 @@ static int tomoyo_check_double_path_acl(
 		error = 0;
 		break;
 	}
-	up_read(&tomoyo_domain_acl_info_list_lock);
+	up_read(&tomoyo_policy_lock);
+	/***** READER SECTION END *****/
 	return error;
 }
 
@@ -980,8 +994,12 @@ static int tomoyo_check_single_path_perm
 		       tomoyo_get_msg(is_enforce), msg, filename->name,
 		       tomoyo_get_last_name(domain));
 	if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) {
-		const char *name = tomoyo_get_file_pattern(filename)->name;
-		tomoyo_update_single_path_acl(operation, name, domain, false);
+		struct tomoyo_cookie cookie;
+		tomoyo_add_cookie(&cookie, filename);
+		tomoyo_get_file_pattern(&cookie);
+		tomoyo_update_single_path_acl(operation, cookie.u.path->name,
+					      domain, false);
+		tomoyo_del_cookie(&cookie);
 	}
 	if (!is_enforce)
 		error = 0;
@@ -1227,10 +1245,17 @@ int tomoyo_check_2path_perm(struct tomoy
 		       msg, buf1->name, buf2->name,
 		       tomoyo_get_last_name(domain));
 	if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) {
-		const char *name1 = tomoyo_get_file_pattern(buf1)->name;
-		const char *name2 = tomoyo_get_file_pattern(buf2)->name;
-		tomoyo_update_double_path_acl(operation, name1, name2, domain,
+		struct tomoyo_cookie cookie1;
+		struct tomoyo_cookie cookie2;
+		tomoyo_add_cookie(&cookie1, buf1);
+		tomoyo_add_cookie(&cookie2, buf2);
+		tomoyo_get_file_pattern(&cookie1);
+		tomoyo_get_file_pattern(&cookie2);
+		tomoyo_update_double_path_acl(operation, cookie1.u.path->name,
+					      cookie2.u.path->name, domain,
 					      false);
+		tomoyo_del_cookie(&cookie1);
+		tomoyo_del_cookie(&cookie2);
 	}
  out:
 	tomoyo_free(buf1);
--- security-testing-2.6.git.orig/security/tomoyo/realpath.c
+++ security-testing-2.6.git/security/tomoyo/realpath.c
@@ -14,6 +14,7 @@
 #include <linux/mnt_namespace.h>
 #include <linux/fs_struct.h>
 #include "common.h"
+#include "tomoyo.h"
 #include "realpath.h"
 
 /**
@@ -195,70 +196,49 @@ char *tomoyo_realpath_nofollow(const cha
 }
 
 /* Memory allocated for non-string data. */
-static unsigned int tomoyo_allocated_memory_for_elements;
+static atomic_t tomoyo_private_memory_size;
 /* Quota for holding non-string data. */
-static unsigned int tomoyo_quota_for_elements;
+static unsigned int tomoyo_private_memory_quota;
 
 /**
- * tomoyo_alloc_element - Allocate permanent memory for structures.
+ * tomoyo_alloc_element - Commit memory for elements.
  *
- * @size: Size in bytes.
+ * @ptr: Pointer to allocated memory. Maybe NULL.
  *
- * Returns pointer to allocated memory on success, NULL otherwise.
+ * Returns true if @ptr is not NULL and quota not exceeded, false otherwise.
  *
- * Memory has to be zeroed.
- * The RAM is chunked, so NEVER try to kfree() the returned pointer.
+ * Caller must add @ptr to an appropriate list if this function returned true.
  */
-void *tomoyo_alloc_element(const unsigned int size)
+bool tomoyo_alloc_element(const void *ptr)
 {
-	static char *buf;
-	static DEFINE_MUTEX(lock);
-	static unsigned int buf_used_len = PATH_MAX;
-	char *ptr = NULL;
-	/*Assumes sizeof(void *) >= sizeof(long) is true. */
-	const unsigned int word_aligned_size
-		= roundup(size, max(sizeof(void *), sizeof(long)));
-	if (word_aligned_size > PATH_MAX)
-		return NULL;
-	/***** EXCLUSIVE SECTION START *****/
-	mutex_lock(&lock);
-	if (buf_used_len + word_aligned_size > PATH_MAX) {
-		if (!tomoyo_quota_for_elements ||
-		    tomoyo_allocated_memory_for_elements
-		    + PATH_MAX <= tomoyo_quota_for_elements)
-			ptr = kzalloc(PATH_MAX, GFP_KERNEL);
-		if (!ptr) {
-			printk(KERN_WARNING "ERROR: Out of memory "
-			       "for tomoyo_alloc_element().\n");
-			if (!tomoyo_policy_loaded)
-				panic("MAC Initialization failed.\n");
-		} else {
-			buf = ptr;
-			tomoyo_allocated_memory_for_elements += PATH_MAX;
-			buf_used_len = word_aligned_size;
-			ptr = buf;
-		}
-	} else if (word_aligned_size) {
-		int i;
-		ptr = buf + buf_used_len;
-		buf_used_len += word_aligned_size;
-		for (i = 0; i < word_aligned_size; i++) {
-			if (!ptr[i])
-				continue;
-			printk(KERN_ERR "WARNING: Reserved memory was tainted! "
-			       "The system might go wrong.\n");
-			ptr[i] = '\0';
-		}
-	}
-	mutex_unlock(&lock);
-	/***** EXCLUSIVE SECTION END *****/
-	return ptr;
+	const int len = ptr ? ksize(ptr) : 0;
+	atomic_add(len, &tomoyo_private_memory_size);
+	if (len && (!tomoyo_private_memory_quota ||
+		    atomic_read(&tomoyo_private_memory_size)
+		    <= tomoyo_private_memory_quota))
+		return true;
+	atomic_sub(len, &tomoyo_private_memory_size);
+	printk(KERN_WARNING "ERROR: Out of memory. (%s)\n", __func__);
+	if (!tomoyo_policy_loaded)
+		panic("MAC Initialization failed.\n");
+	return false;
+}
+
+/**
+ * tomoyo_free_element - Free memory for elements.
+ *
+ * @ptr: Pointer to allocated memory.
+ */
+static void tomoyo_free_element(const void *ptr)
+{
+	atomic_sub(ksize(ptr), &tomoyo_private_memory_size);
+	kfree(ptr);
 }
 
 /* Memory allocated for string data in bytes. */
-static unsigned int tomoyo_allocated_memory_for_savename;
+static atomic_t tomoyo_shared_memory_size;
 /* Quota for holding string data in bytes. */
-static unsigned int tomoyo_quota_for_savename;
+static unsigned int tomoyo_shared_memory_quota;
 
 /*
  * TOMOYO uses this hash only when appending a string into the string
@@ -270,104 +250,102 @@ static unsigned int tomoyo_quota_for_sav
 /* Structure for string data. */
 struct tomoyo_name_entry {
 	struct list_head list;
+	atomic_t users;
 	struct tomoyo_path_info entry;
 };
 
-/* Structure for available memory region. */
-struct tomoyo_free_memory_block_list {
-	struct list_head list;
-	char *ptr;             /* Pointer to a free area. */
-	int len;               /* Length of the area.     */
-};
-
-/*
- * The list for "struct tomoyo_name_entry".
- *
- * This list is updated only inside tomoyo_save_name(), thus
- * no global mutex exists.
- */
+/* The list for "struct tomoyo_name_entry". */
 static struct list_head tomoyo_name_list[TOMOYO_MAX_HASH];
+static DEFINE_MUTEX(tomoyo_name_list_lock);
 
 /**
- * tomoyo_save_name - Allocate permanent memory for string data.
+ * tomoyo_get_name - Allocate shared memory for string data.
  *
- * @name: The string to store into the permernent memory.
+ * @name: The string to add.
  *
  * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise.
- *
- * The RAM is shared, so NEVER try to modify or kfree() the returned name.
  */
-const struct tomoyo_path_info *tomoyo_save_name(const char *name)
+const struct tomoyo_path_info *tomoyo_get_name(const char *name)
 {
-	static LIST_HEAD(fmb_list);
-	static DEFINE_MUTEX(lock);
+	struct tomoyo_name_entry *entry;
 	struct tomoyo_name_entry *ptr;
 	unsigned int hash;
-	/* fmb contains available size in bytes.
-	   fmb is removed from the fmb_list when fmb->len becomes 0. */
-	struct tomoyo_free_memory_block_list *fmb;
 	int len;
-	char *cp;
+	int allocated_len;
+	int error = -ENOMEM;
 
 	if (!name)
 		return NULL;
 	len = strlen(name) + 1;
 	if (len > TOMOYO_MAX_PATHNAME_LEN) {
-		printk(KERN_WARNING "ERROR: Name too long "
-		       "for tomoyo_save_name().\n");
+		printk(KERN_WARNING "ERROR: Name too long. (%s)\n", __func__);
 		return NULL;
 	}
 	hash = full_name_hash((const unsigned char *) name, len - 1);
+	entry = kmalloc(sizeof(*entry) + len, GFP_KERNEL);
+	allocated_len = entry ? ksize(entry) : 0;
 	/***** EXCLUSIVE SECTION START *****/
-	mutex_lock(&lock);
+	mutex_lock(&tomoyo_name_list_lock);
 	list_for_each_entry(ptr, &tomoyo_name_list[hash % TOMOYO_MAX_HASH],
-			     list) {
-		if (hash == ptr->entry.hash && !strcmp(name, ptr->entry.name))
-			goto out;
-	}
-	list_for_each_entry(fmb, &fmb_list, list) {
-		if (len <= fmb->len)
-			goto ready;
-	}
-	if (!tomoyo_quota_for_savename ||
-	    tomoyo_allocated_memory_for_savename + PATH_MAX
-	    <= tomoyo_quota_for_savename)
-		cp = kzalloc(PATH_MAX, GFP_KERNEL);
-	else
-		cp = NULL;
-	fmb = kzalloc(sizeof(*fmb), GFP_KERNEL);
-	if (!cp || !fmb) {
-		kfree(cp);
-		kfree(fmb);
-		printk(KERN_WARNING "ERROR: Out of memory "
-		       "for tomoyo_save_name().\n");
+			    list) {
+		if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name))
+			continue;
+		atomic_inc(&ptr->users);
+		error = 0;
+		break;
+	}
+	if (error && entry &&
+	    (!tomoyo_shared_memory_quota ||
+	     atomic_read(&tomoyo_shared_memory_size) + allocated_len
+	     <= tomoyo_shared_memory_quota)) {
+		atomic_add(allocated_len, &tomoyo_shared_memory_size);
+		ptr = entry;
+		memset(ptr, 0, sizeof(*ptr));
+		ptr->entry.name = ((char *) ptr) + sizeof(*ptr);
+		memmove((char *) ptr->entry.name, name, len);
+		atomic_set(&ptr->users, 1);
+		tomoyo_fill_path_info(&ptr->entry);
+		list_add_tail(&ptr->list,
+			      &tomoyo_name_list[hash % TOMOYO_MAX_HASH]);
+		entry = NULL;
+		error = 0;
+	}
+	mutex_unlock(&tomoyo_name_list_lock);
+	/***** EXCLUSIVE SECTION END *****/
+	if (error) {
+		printk(KERN_WARNING "ERROR: Out of memory. (%s)\n", __func__);
 		if (!tomoyo_policy_loaded)
 			panic("MAC Initialization failed.\n");
-		ptr = NULL;
-		goto out;
 	}
-	tomoyo_allocated_memory_for_savename += PATH_MAX;
-	list_add(&fmb->list, &fmb_list);
-	fmb->ptr = cp;
-	fmb->len = PATH_MAX;
- ready:
-	ptr = tomoyo_alloc_element(sizeof(*ptr));
-	if (!ptr)
-		goto out;
-	ptr->entry.name = fmb->ptr;
-	memmove(fmb->ptr, name, len);
-	tomoyo_fill_path_info(&ptr->entry);
-	fmb->ptr += len;
-	fmb->len -= len;
-	list_add_tail(&ptr->list, &tomoyo_name_list[hash % TOMOYO_MAX_HASH]);
-	if (fmb->len == 0) {
-		list_del(&fmb->list);
-		kfree(fmb);
+	kfree(entry);
+	return ptr ? &ptr->entry : NULL;
+}
+
+/**
+ * tomoyo_put_name - Delete shared memory for string data.
+ *
+ * @ptr: Pointer to "struct tomoyo_path_info".
+ */
+void tomoyo_put_name(const struct tomoyo_path_info *name)
+{
+	struct tomoyo_name_entry *ptr;
+	bool can_delete = false;
+
+	if (!name)
+		return;
+	ptr = container_of(name, struct tomoyo_name_entry, entry);
+	/***** EXCLUSIVE SECTION START *****/
+	mutex_lock(&tomoyo_name_list_lock);
+	if (atomic_dec_and_test(&ptr->users)) {
+		list_del(&ptr->list);
+		can_delete = true;
 	}
- out:
-	mutex_unlock(&lock);
+	mutex_unlock(&tomoyo_name_list_lock);
 	/***** EXCLUSIVE SECTION END *****/
-	return ptr ? &ptr->entry : NULL;
+	if (can_delete) {
+		atomic_sub(ksize(ptr), &tomoyo_shared_memory_size);
+		kfree(ptr);
+	}
 }
 
 /**
@@ -376,17 +354,18 @@ const struct tomoyo_path_info *tomoyo_sa
 void __init tomoyo_realpath_init(void)
 {
 	int i;
+	struct tomoyo_cookie cookie;
 
 	BUILD_BUG_ON(TOMOYO_MAX_PATHNAME_LEN > PATH_MAX);
 	for (i = 0; i < TOMOYO_MAX_HASH; i++)
 		INIT_LIST_HEAD(&tomoyo_name_list[i]);
 	INIT_LIST_HEAD(&tomoyo_kernel_domain.acl_info_list);
-	tomoyo_kernel_domain.domainname = tomoyo_save_name(TOMOYO_ROOT_NAME);
+	/* No lock needed because this is security_initcall() phase. */
+	tomoyo_kernel_domain.domainname = tomoyo_get_name(TOMOYO_ROOT_NAME);
 	list_add_tail(&tomoyo_kernel_domain.list, &tomoyo_domain_list);
-	down_read(&tomoyo_domain_list_lock);
-	if (tomoyo_find_domain(TOMOYO_ROOT_NAME) != &tomoyo_kernel_domain)
+	if (!tomoyo_find_domain(TOMOYO_ROOT_NAME, &cookie) ||
+	    cookie.u.domain != &tomoyo_kernel_domain)
 		panic("Can't register tomoyo_kernel_domain");
-	up_read(&tomoyo_domain_list_lock);
 }
 
 /* Memory allocated for temporary purpose. */
@@ -433,25 +412,25 @@ int tomoyo_read_memory_counter(struct to
 {
 	if (!head->read_eof) {
 		const unsigned int shared
-			= tomoyo_allocated_memory_for_savename;
+			= atomic_read(&tomoyo_shared_memory_size);
 		const unsigned int private
-			= tomoyo_allocated_memory_for_elements;
+			= atomic_read(&tomoyo_private_memory_size);
 		const unsigned int dynamic
 			= atomic_read(&tomoyo_dynamic_memory_size);
 		char buffer[64];
 
 		memset(buffer, 0, sizeof(buffer));
-		if (tomoyo_quota_for_savename)
+		if (tomoyo_shared_memory_quota)
 			snprintf(buffer, sizeof(buffer) - 1,
 				 "   (Quota: %10u)",
-				 tomoyo_quota_for_savename);
+				 tomoyo_shared_memory_quota);
 		else
 			buffer[0] = '\0';
 		tomoyo_io_printf(head, "Shared:  %10u%s\n", shared, buffer);
-		if (tomoyo_quota_for_elements)
+		if (tomoyo_private_memory_quota)
 			snprintf(buffer, sizeof(buffer) - 1,
 				 "   (Quota: %10u)",
-				 tomoyo_quota_for_elements);
+				 tomoyo_private_memory_quota);
 		else
 			buffer[0] = '\0';
 		tomoyo_io_printf(head, "Private: %10u%s\n", private, buffer);
@@ -476,8 +455,330 @@ int tomoyo_write_memory_quota(struct tom
 	unsigned int size;
 
 	if (sscanf(data, "Shared: %u", &size) == 1)
-		tomoyo_quota_for_savename = size;
+		tomoyo_shared_memory_quota = size;
 	else if (sscanf(data, "Private: %u", &size) == 1)
-		tomoyo_quota_for_elements = size;
+		tomoyo_private_memory_quota = size;
 	return 0;
 }
+
+/* List of pointers referenced by cookies. */
+static LIST_HEAD(tomoyo_cookie_list);
+static DEFINE_RWLOCK(tomoyo_cookie_list_lock);
+
+/**
+ * tomoyo_add_cookie - Add a cookie to cookie list.
+ *
+ * @cookie: Pointer to "struct tomoyo_cookie".
+ * @ptr:    Pointer to assign. Maybe NULL.
+ */
+void tomoyo_add_cookie(struct tomoyo_cookie *cookie, const void *ptr)
+{
+	unsigned long flags;
+	if (!cookie)
+		return;
+	cookie->u.ptr = ptr;
+	write_lock_irqsave(&tomoyo_cookie_list_lock, flags);
+	list_add_tail(&cookie->list, &tomoyo_cookie_list);
+	write_unlock_irqrestore(&tomoyo_cookie_list_lock, flags);
+}
+
+/**
+ * tomoyo_del_cookie - Delete a cookie from cookie list.
+ *
+ * @cookie: Pointer to "struct tomoyo_cookie".
+ */
+void tomoyo_del_cookie(struct tomoyo_cookie *cookie)
+{
+	unsigned long flags;
+	if (!cookie)
+		return;
+	write_lock_irqsave(&tomoyo_cookie_list_lock, flags);
+	list_del(&cookie->list);
+	write_unlock_irqrestore(&tomoyo_cookie_list_lock, flags);
+}
+
+/**
+ * tomoyo_used_by_cookie - Check whether the given pointer is referenced by a cookie or not.
+ *
+ * @ptr: Pointer to check.
+ *
+ * Returns true if @ptr is in use, false otherwise.
+ *
+ * Caller must hold tomoyo_policy_lock for writing.
+ */
+static bool tomoyo_used_by_cookie(const void *ptr)
+{
+	/***** WRITER SECTION START *****/
+	unsigned long flags;
+	struct tomoyo_cookie *cookie;
+	bool in_use = false;
+	read_lock_irqsave(&tomoyo_cookie_list_lock, flags);
+	list_for_each_entry(cookie, &tomoyo_cookie_list, list) {
+		if (ptr != cookie->u.ptr)
+			continue;
+		in_use = true;
+		break;
+	}
+	read_unlock_irqrestore(&tomoyo_cookie_list_lock, flags);
+	return in_use;
+	/***** WRITER SECTION END *****/
+}
+
+/**
+ * tomoyo_cleanup_allow_read - Clean up deleted "struct tomoyo_globally_readable_file_entry".
+ */
+static void tomoyo_cleanup_allow_read(void)
+{
+	struct tomoyo_globally_readable_file_entry *ptr;
+	struct tomoyo_globally_readable_file_entry *tmp;
+	LIST_HEAD(q);
+	/***** WRITER SECTION START *****/
+	down_write(&tomoyo_policy_lock);
+	list_for_each_entry_safe(ptr, tmp, &tomoyo_globally_readable_list,
+				 list) {
+		if (!ptr->is_deleted || tomoyo_used_by_cookie(ptr))
+			continue;
+		list_del(&ptr->list);
+		list_add(&ptr->list, &q);
+	}
+	up_write(&tomoyo_policy_lock);
+	/***** WRITER SECTION END *****/
+	list_for_each_entry_safe(ptr, tmp, &q, list) {
+		tomoyo_put_name(ptr->filename);
+		list_del(&ptr->list);
+		tomoyo_free_element(ptr);
+	}
+}
+
+/**
+ * tomoyo_cleanup_file_pattern - Clean up deleted "struct tomoyo_pattern_entry".
+ */
+static void tomoyo_cleanup_file_pattern(void)
+{
+	struct tomoyo_pattern_entry *ptr;
+	struct tomoyo_pattern_entry *tmp;
+	LIST_HEAD(q);
+	/***** WRITER SECTION START *****/
+	down_write(&tomoyo_policy_lock);
+	list_for_each_entry_safe(ptr, tmp, &tomoyo_pattern_list, list) {
+		if (!ptr->is_deleted || tomoyo_used_by_cookie(ptr))
+			continue;
+		list_del(&ptr->list);
+		list_add(&ptr->list, &q);
+	}
+	up_write(&tomoyo_policy_lock);
+	/***** WRITER SECTION END *****/
+	list_for_each_entry_safe(ptr, tmp, &q, list) {
+		tomoyo_put_name(ptr->pattern);
+		list_del(&ptr->list);
+		tomoyo_free_element(ptr);
+	}
+}
+
+/**
+ * tomoyo_cleanup_no_rewrite - Clean up deleted "struct tomoyo_no_rewrite_entry".
+ */
+static void tomoyo_cleanup_no_rewrite(void)
+{
+	struct tomoyo_no_rewrite_entry *ptr;
+	struct tomoyo_no_rewrite_entry *tmp;
+	LIST_HEAD(q);
+	/***** WRITER SECTION START *****/
+	down_write(&tomoyo_policy_lock);
+	list_for_each_entry_safe(ptr, tmp, &tomoyo_no_rewrite_list, list) {
+		if (!ptr->is_deleted || tomoyo_used_by_cookie(ptr))
+			continue;
+		list_del(&ptr->list);
+		list_add(&ptr->list, &q);
+	}
+	up_write(&tomoyo_policy_lock);
+	/***** WRITER SECTION END *****/
+	list_for_each_entry_safe(ptr, tmp, &q, list) {
+		tomoyo_put_name(ptr->pattern);
+		list_del(&ptr->list);
+		tomoyo_free_element(ptr);
+	}
+}
+
+/**
+ * tomoyo_cleanup_initializer - Clean up deleted "struct tomoyo_domain_initializer_entry".
+ */
+static void tomoyo_cleanup_initializer(void)
+{
+	struct tomoyo_domain_initializer_entry *ptr;
+	struct tomoyo_domain_initializer_entry *tmp;
+	LIST_HEAD(q);
+	/***** WRITER SECTION START *****/
+	down_write(&tomoyo_policy_lock);
+	list_for_each_entry_safe(ptr, tmp, &tomoyo_domain_initializer_list,
+				 list) {
+		if (!ptr->is_deleted || tomoyo_used_by_cookie(ptr))
+			continue;
+		list_del(&ptr->list);
+		list_add(&ptr->list, &q);
+	}
+	up_write(&tomoyo_policy_lock);
+	/***** WRITER SECTION END *****/
+	list_for_each_entry_safe(ptr, tmp, &q, list) {
+		tomoyo_put_name(ptr->domainname);
+		tomoyo_put_name(ptr->program);
+		list_del(&ptr->list);
+		tomoyo_free_element(ptr);
+	}
+}
+
+/**
+ * tomoyo_cleanup_keep_domain - Clean up deleted "struct tomoyo_domain_keeper_entry".
+ */
+static void tomoyo_cleanup_keep_domain(void)
+{
+	struct tomoyo_domain_keeper_entry *ptr;
+	struct tomoyo_domain_keeper_entry *tmp;
+	LIST_HEAD(q);
+	/***** WRITER SECTION START *****/
+	down_write(&tomoyo_policy_lock);
+	list_for_each_entry_safe(ptr, tmp, &tomoyo_domain_keeper_list, list) {
+		if (!ptr->is_deleted || tomoyo_used_by_cookie(ptr))
+			continue;
+		list_del(&ptr->list);
+		list_add(&ptr->list, &q);
+	}
+	up_write(&tomoyo_policy_lock);
+	/***** WRITER SECTION END *****/
+	list_for_each_entry_safe(ptr, tmp, &q, list) {
+		tomoyo_put_name(ptr->domainname);
+		tomoyo_put_name(ptr->program);
+		list_del(&ptr->list);
+		tomoyo_free_element(ptr);
+	}
+}
+
+/**
+ * tomoyo_cleanup_alias - Clean up deleted "struct tomoyo_alias_entry".
+ */
+static void tomoyo_cleanup_alias(void)
+{
+	struct tomoyo_alias_entry *ptr;
+	struct tomoyo_alias_entry *tmp;
+	LIST_HEAD(q);
+	/***** WRITER SECTION START *****/
+	down_write(&tomoyo_policy_lock);
+	list_for_each_entry_safe(ptr, tmp, &tomoyo_alias_list, list) {
+		if (!ptr->is_deleted || tomoyo_used_by_cookie(ptr))
+			continue;
+		list_del(&ptr->list);
+		list_add(&ptr->list, &q);
+	}
+	up_write(&tomoyo_policy_lock);
+	/***** WRITER SECTION END *****/
+	list_for_each_entry_safe(ptr, tmp, &q, list) {
+		tomoyo_put_name(ptr->original_name);
+		tomoyo_put_name(ptr->aliased_name);
+		list_del(&ptr->list);
+		tomoyo_free_element(ptr);
+	}
+}
+
+/**
+ * tomoyo_cleanup_manager - Clean up deleted "struct tomoyo_policy_manager_entry".
+ */
+static void tomoyo_cleanup_manager(void)
+{
+	struct tomoyo_policy_manager_entry *ptr;
+	struct tomoyo_policy_manager_entry *tmp;
+	LIST_HEAD(q);
+	/***** WRITER SECTION START *****/
+	down_write(&tomoyo_policy_lock);
+	list_for_each_entry_safe(ptr, tmp, &tomoyo_policy_manager_list, list) {
+		if (!ptr->is_deleted || tomoyo_used_by_cookie(ptr))
+			continue;
+		list_del(&ptr->list);
+		list_add(&ptr->list, &q);
+	}
+	up_write(&tomoyo_policy_lock);
+	/***** WRITER SECTION END *****/
+	list_for_each_entry_safe(ptr, tmp, &q, list) {
+		tomoyo_put_name(ptr->manager);
+		list_del(&ptr->list);
+		tomoyo_free_element(ptr);
+	}
+}
+
+/**
+ * tomoyo_cleanup_domain_policy - Clean up deleted domain policy.
+ */
+static void tomoyo_cleanup_domain_policy(void)
+{
+	struct tomoyo_domain_info *domain;
+	struct tomoyo_domain_info *next_domain;
+	struct tomoyo_acl_info *acl;
+	struct tomoyo_acl_info *next_acl;
+	LIST_HEAD(q_domain);
+	LIST_HEAD(q_acl);
+	/***** WRITER SECTION START *****/
+	down_write(&tomoyo_policy_lock);
+	list_for_each_entry_safe(domain, next_domain, &tomoyo_domain_list,
+				 list) {
+		const bool can_delete_domain = domain->is_deleted &&
+			!tomoyo_used_by_cookie(domain);
+		if (can_delete_domain) {
+			list_for_each_entry(acl, &domain->acl_info_list, list)
+				acl->type |= TOMOYO_ACL_DELETED;
+		}
+		list_for_each_entry_safe(acl, next_acl, &domain->acl_info_list,
+					 list) {
+			if (!(acl->type & TOMOYO_ACL_DELETED)
+			    || tomoyo_used_by_cookie(acl))
+				continue;
+			list_del(&acl->list);
+			list_add(&acl->list, &q_acl);
+		}
+		if (can_delete_domain && list_empty(&domain->acl_info_list)) {
+			list_del(&domain->list);
+			list_add(&domain->list, &q_domain);
+		}
+	}
+	up_write(&tomoyo_policy_lock);
+	/***** WRITER SECTION END *****/
+	list_for_each_entry_safe(acl, next_acl, &q_acl, list) {
+		switch (tomoyo_acl_type1(acl)) {
+			struct tomoyo_single_path_acl_record *acl1;
+			struct tomoyo_double_path_acl_record *acl2;
+		case TOMOYO_TYPE_SINGLE_PATH_ACL:
+			acl1 = container_of(acl,
+				    struct tomoyo_single_path_acl_record,
+					    head);
+			tomoyo_put_name(acl1->filename);
+			break;
+		case TOMOYO_TYPE_DOUBLE_PATH_ACL:
+			acl2 = container_of(acl,
+				    struct tomoyo_double_path_acl_record,
+					    head);
+			tomoyo_put_name(acl2->filename1);
+			tomoyo_put_name(acl2->filename2);
+			break;
+		}
+		list_del(&acl->list);
+		tomoyo_free_element(acl);
+	}
+	list_for_each_entry_safe(domain, next_domain, &q_domain, list) {
+		tomoyo_put_name(domain->domainname);
+		list_del(&domain->list);
+		tomoyo_free_element(domain);
+	}
+}
+
+/**
+ * tomoyo_run_garbage_collector - Run garbage collector.
+ */
+void tomoyo_run_garbage_collector(void)
+{
+	tomoyo_cleanup_allow_read();
+	tomoyo_cleanup_file_pattern();
+	tomoyo_cleanup_no_rewrite();
+	tomoyo_cleanup_initializer();
+	tomoyo_cleanup_keep_domain();
+	tomoyo_cleanup_alias();
+	tomoyo_cleanup_manager();
+	tomoyo_cleanup_domain_policy();
+}
--- security-testing-2.6.git.orig/security/tomoyo/realpath.h
+++ security-testing-2.6.git/security/tomoyo/realpath.h
@@ -36,18 +36,6 @@ char *tomoyo_realpath_nofollow(const cha
 /* Same with tomoyo_realpath() except that the pathname is already solved. */
 char *tomoyo_realpath_from_path(struct path *path);
 
-/*
- * Allocate memory for ACL entry.
- * The RAM is chunked, so NEVER try to kfree() the returned pointer.
- */
-void *tomoyo_alloc_element(const unsigned int size);
-
-/*
- * Keep the given name on the RAM.
- * The RAM is shared, so NEVER try to modify or kfree() the returned name.
- */
-const struct tomoyo_path_info *tomoyo_save_name(const char *name);
-
 /* Allocate memory for temporary use (e.g. permission checks). */
 void *tomoyo_alloc(const size_t size);
 
@@ -63,4 +51,17 @@ int tomoyo_write_memory_quota(struct tom
 /* Initialize realpath related code. */
 void __init tomoyo_realpath_init(void);
 
+/* Check memory quota. */
+bool tomoyo_alloc_element(const void *ptr);
+
+/* Allocate memory for the given name. */
+const struct tomoyo_path_info *tomoyo_get_name(const char *name);
+/* Delete memory for the given name. */
+void tomoyo_put_name(const struct tomoyo_path_info *name);
+
+/* Add a cookie to cookie list. */
+void tomoyo_add_cookie(struct tomoyo_cookie *cookie, const void *ptr);
+/* Delete a cookie from cookie list. */
+void tomoyo_del_cookie(struct tomoyo_cookie *cookie);
+
 #endif /* !defined(_SECURITY_TOMOYO_REALPATH_H) */
--- security-testing-2.6.git.orig/security/tomoyo/tomoyo.c
+++ security-testing-2.6.git/security/tomoyo/tomoyo.c
@@ -17,14 +17,23 @@
 static int tomoyo_cred_prepare(struct cred *new, const struct cred *old,
 			       gfp_t gfp)
 {
-	/*
-	 * Since "struct tomoyo_domain_info *" is a sharable pointer,
-	 * we don't need to duplicate.
-	 */
-	new->security = old->security;
+	struct tomoyo_cookie *cookie = kzalloc(sizeof(*cookie), gfp);
+
+	if (!cookie)
+		return -ENOMEM;
+	tomoyo_add_cookie(cookie,
+			  ((struct tomoyo_cookie *) old->security)->u.ptr);
+	new->security = cookie;
 	return 0;
 }
 
+static void tomoyo_cred_free(struct cred *cred)
+{
+	struct tomoyo_cookie *cookie = cred->security;
+	tomoyo_del_cookie(cookie);
+	kfree(cookie);
+}
+
 static int tomoyo_bprm_set_creds(struct linux_binprm *bprm)
 {
 	/*
@@ -43,26 +52,21 @@ static int tomoyo_bprm_set_creds(struct 
 	 * Tell tomoyo_bprm_check_security() is called for the first time of an
 	 * execve operation.
 	 */
-	bprm->cred->security = NULL;
+	((struct tomoyo_cookie *) bprm->cred->security)->u.domain = NULL;
 	return 0;
 }
 
 static int tomoyo_bprm_check_security(struct linux_binprm *bprm)
 {
-	struct tomoyo_domain_info *domain = bprm->cred->security;
+	struct tomoyo_domain_info *domain = ((struct tomoyo_cookie *)
+					     bprm->cred->security)->u.domain;
 
 	/*
 	 * Execute permission is checked against pathname passed to do_execve()
 	 * using current domain.
 	 */
-	if (!domain) {
-		struct tomoyo_domain_info *next_domain = NULL;
-		int retval = tomoyo_find_next_domain(bprm, &next_domain);
-
-		if (!retval)
-			bprm->cred->security = next_domain;
-		return retval;
-	}
+	if (!domain)
+		return tomoyo_find_next_domain(bprm);
 	/*
 	 * Read permission is checked against interpreters using next domain.
 	 * '1' is the result of open_to_namei_flags(O_RDONLY).
@@ -259,6 +263,7 @@ static int tomoyo_dentry_open(struct fil
 static struct security_operations tomoyo_security_ops = {
 	.name                = "tomoyo",
 	.cred_prepare        = tomoyo_cred_prepare,
+	.cred_free           = tomoyo_cred_free,
 	.bprm_set_creds      = tomoyo_bprm_set_creds,
 	.bprm_check_security = tomoyo_bprm_check_security,
 #ifdef CONFIG_SYSCTL
@@ -279,6 +284,7 @@ static struct security_operations tomoyo
 static int __init tomoyo_init(void)
 {
 	struct cred *cred = (struct cred *) current_cred();
+	struct tomoyo_cookie *cookie;
 
 	if (!security_module_enable(&tomoyo_security_ops))
 		return 0;
@@ -286,7 +292,9 @@ static int __init tomoyo_init(void)
 	if (register_security(&tomoyo_security_ops))
 		panic("Failure registering TOMOYO Linux");
 	printk(KERN_INFO "TOMOYO Linux initialized\n");
-	cred->security = &tomoyo_kernel_domain;
+	cookie = kzalloc(sizeof(*cookie), GFP_KERNEL);
+	tomoyo_add_cookie(cookie, &tomoyo_kernel_domain);
+	cred->security = cookie;
 	tomoyo_realpath_init();
 	return 0;
 }
--- security-testing-2.6.git.orig/security/tomoyo/tomoyo.h
+++ security-testing-2.6.git/security/tomoyo/tomoyo.h
@@ -33,8 +33,7 @@ int tomoyo_check_2path_perm(struct tomoy
 			    struct path *path2);
 int tomoyo_check_rewrite_permission(struct tomoyo_domain_info *domain,
 				    struct file *filp);
-int tomoyo_find_next_domain(struct linux_binprm *bprm,
-			    struct tomoyo_domain_info **next_domain);
+int tomoyo_find_next_domain(struct linux_binprm *bprm);
 
 /* Index numbers for Access Controls. */
 
@@ -85,18 +84,14 @@ int tomoyo_find_next_domain(struct linux
 
 extern struct tomoyo_domain_info tomoyo_kernel_domain;
 
-static inline struct tomoyo_domain_info *tomoyo_domain(void)
-{
-	return current_cred()->security;
-}
-
-/* Caller holds tasklist_lock spinlock. */
+/* Caller calls rcu_read_lock()/rcu_read_unlock(). */
 static inline struct tomoyo_domain_info *tomoyo_real_domain(struct task_struct
 							    *task)
 {
 	/***** CRITICAL SECTION START *****/
 	const struct cred *cred = get_task_cred(task);
-	struct tomoyo_domain_info *domain = cred->security;
+	struct tomoyo_domain_info *domain = ((struct tomoyo_cookie *)
+					     cred->security)->u.domain;
 
 	put_cred(cred);
 	return domain;

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH] TOMOYO: Add garbage collector support. (v2)
  2009-05-14 12:08                 ` [PATCH] TOMOYO: Add garbage collector support. (v2) Tetsuo Handa
@ 2009-05-15  1:49                   ` James Morris
  2009-05-16 12:07                     ` Tetsuo Handa
  0 siblings, 1 reply; 34+ messages in thread
From: James Morris @ 2009-05-15  1:49 UTC (permalink / raw)
  To: Tetsuo Handa; +Cc: linux-security-module, linux-kernel

On Thu, 14 May 2009, Tetsuo Handa wrote:

> ---
>  security/tomoyo/common.c   |  456 +++++++++++++++++++-----------------
>  security/tomoyo/common.h   |  134 ++++++++--
>  security/tomoyo/domain.c   |  437 +++++++++++++---------------------
>  security/tomoyo/file.c     |  369 +++++++++++++++--------------
>  security/tomoyo/realpath.c |  567 ++++++++++++++++++++++++++++++++++-----------
>  security/tomoyo/realpath.h |   25 +
>  security/tomoyo/tomoyo.c   |   40 +--
>  security/tomoyo/tomoyo.h   |   13 -
>  8 files changed, 1190 insertions(+), 851 deletions(-)

This seems like an awfully large and invasive patch just to add GC support 
which you didn't originally didn't think was necessary.

I think it needs review from people outside of your project.


- James
-- 
James Morris
<jmorris@namei.org>

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH] TOMOYO: Add garbage collector support. (v2)
  2009-05-15  1:49                   ` James Morris
@ 2009-05-16 12:07                     ` Tetsuo Handa
  2009-05-25  0:37                       ` Tetsuo Handa
  0 siblings, 1 reply; 34+ messages in thread
From: Tetsuo Handa @ 2009-05-16 12:07 UTC (permalink / raw)
  To: jmorris; +Cc: linux-security-module, linux-kernel

James Morris wrote:
> On Thu, 14 May 2009, Tetsuo Handa wrote:
> 
> > ---
> >  security/tomoyo/common.c   |  456 +++++++++++++++++++-----------------
> >  security/tomoyo/common.h   |  134 ++++++++--
> >  security/tomoyo/domain.c   |  437 +++++++++++++---------------------
> >  security/tomoyo/file.c     |  369 +++++++++++++++--------------
> >  security/tomoyo/realpath.c |  567 ++++++++++++++++++++++++++++++++++-----------
> >  security/tomoyo/realpath.h |   25 +
> >  security/tomoyo/tomoyo.c   |   40 +--
> >  security/tomoyo/tomoyo.h   |   13 -
> >  8 files changed, 1190 insertions(+), 851 deletions(-)
> 
> This seems like an awfully large and invasive patch just to add GC support 
> which you didn't originally didn't think was necessary.
> 
> I think it needs review from people outside of your project.

I see. Would somebody please review?

For reviewers help, here is my thinking.



As of #15's posting ( http://lkml.org/lkml/2009/2/5/61 ), I was not aware that
use of kmalloc(GFP_KERNEL) with a lock held is not preferable.

For example, 2.6.30-rc6/security/tomoyo/tomoyo.c has below code.

  static int tomoyo_update_single_path_acl(const u8 type, const char *filename,
  					 struct tomoyo_domain_info *
  					 const domain, const bool is_delete)
  {
  	...(snipped)...
  	/***** EXCLUSIVE SECTION START *****/
  	down_write(&tomoyo_domain_acl_info_list_lock);
  	if (is_delete)
  		goto delete;
  	list_for_each_entry(ptr, &domain->acl_info_list, list) {
  		...(snipped)...
  		error = 0;
  		goto out;
  	}
  	/* Not found. Append it to the tail. */
  	acl = tomoyo_alloc_acl_element(TOMOYO_TYPE_SINGLE_PATH_ACL);
  	if (!acl)
  		goto out;
  	...(snipped)...
  	list_add_tail(&acl->head.list, &domain->acl_info_list);
  	error = 0;
  	goto out;
   delete:
  	...(snipped)...
   out:
  	up_write(&tomoyo_domain_acl_info_list_lock);
  	/***** EXCLUSIVE SECTION END *****/
  	return error;
  }

tomoyo_alloc_acl_element() (which calls kmalloc(GFP_KERNEL)) is called with
tomoyo_domain_acl_info_list_lock lock held. And that lock is used like

  static int tomoyo_check_single_path_acl2(const struct tomoyo_domain_info *
  					 domain,
  					 const struct tomoyo_path_info *
  					 filename,
  					 const u16 perm,
  					 const bool may_use_pattern)
  {
    	...(snipped)...
  	down_read(&tomoyo_domain_acl_info_list_lock);
  	list_for_each_entry(ptr, &domain->acl_info_list, list) {
  	  	...(snipped)...
  		error = 0;
  		break;
  	}
  	up_read(&tomoyo_domain_acl_info_list_lock);
  	return error;
  }

This means that when we update TOMOYO's policy (via learning mode or via
/sys/kernel/security/tomoyo/ interface) we might experience a situation where
multiple processes are sleeping for undefined duration if one process went into
sleep state at kmalloc(GFP_KERNEL) in tomoyo_alloc_acl_element() and then
another process went into sleep state at down_read() in
tomoyo_check_single_path_acl2() because of down_write().

This is not a dead lock, but is not preferable.
Away from the discussion whether TOMOYO needs GC or not,
I think TOMOYO should not block reader processes for undefined duration.



TOMOYO will not block reader processes for undefined duration if we call
tomoyo_alloc_acl_element() before down_write(), but that memory will remain
unused if that memory was not added to the list. We cannot release memory
allocated by tomoyo_alloc_acl_element() because tomoyo_alloc_acl_element()
returns requested memory from memory block obtained by kmalloc(PATH_MAX).
tomoyo_alloc_acl_element() is good for minimizing memory usage, but is not
good for releasing unused memory.

TOMOYO will not block reader processes for undefined duration if a writer
process allocates memory before down_write() and releases after up_write()
if the allocated memory was not added to the list.
Thus, I replaced tomoyo_alloc_acl_element() with kmalloc()/kfree() in this
patch. And now, the only reason TOMOYO cannot release memory is that TOMOYO
cannot determine whether memory allocated by kmalloc() is referred by
other processes or not.

Since I replaced tomoyo_alloc_acl_element() with kmalloc()/kfree()
(in order to avoid sleeping operations within a semaphore protected code),
I think TOMOYO is now likely to be able to have GC support (and I also
included the GC in this patch).

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH] TOMOYO: Add garbage collector support. (v2)
  2009-05-16 12:07                     ` Tetsuo Handa
@ 2009-05-25  0:37                       ` Tetsuo Handa
  2009-05-25  0:39                         ` Tetsuo Handa
  0 siblings, 1 reply; 34+ messages in thread
From: Tetsuo Handa @ 2009-05-25  0:37 UTC (permalink / raw)
  To: jmorris; +Cc: linux-security-module, linux-kernel

------- Forwarded Message

Serge E. Hallyn wrote:
> Quoting Tetsuo Handa (penguin-kernel@I-love.SAKURA.ne.jp):
> > James Morris wrote:
> > > On Thu, 14 May 2009, Tetsuo Handa wrote:
> > > 
> > > > ---
> > > >  security/tomoyo/common.c   |  456 +++++++++++++++++++-----------------
> > > >  security/tomoyo/common.h   |  134 ++++++++--
> > > >  security/tomoyo/domain.c   |  437 +++++++++++++---------------------
> > > >  security/tomoyo/file.c     |  369 +++++++++++++++--------------
> > > >  security/tomoyo/realpath.c |  567 ++++++++++++++++++++++++++++++++++-----------
> > > >  security/tomoyo/realpath.h |   25 +
> > > >  security/tomoyo/tomoyo.c   |   40 +--
> > > >  security/tomoyo/tomoyo.h   |   13 -
> > > >  8 files changed, 1190 insertions(+), 851 deletions(-)
> > > 
> > > This seems like an awfully large and invasive patch just to add GC support 
> > > which you didn't originally didn't think was necessary.
> > > 
> > > I think it needs review from people outside of your project.
> > 
> > I see. Would somebody please review?
> 
> Please resend to me privately.  (I've deleted it)
> 
> -serge
> 
Sure.

The key points are:

  (1) Should TOMOYO avoid sleeping operations inside a semaphore?

      Until #14, TOMOYO was using singly linked list and thus reader process
      did not require any locks. But in #15, TOMOYO is using standard doubly
      linked list and thus reader process requires a semaphore. This might
      dull the system's response. In this patch, I moved sleeping operations
      (i.e. kmalloc(GFP_KERNEL)/kfree()) to outside the semaphore protected
      code.

  (2) Should TOMOYO have GC support?

      Several reviewers had been asking me that TOMOYO should release memory
      used by deleted policy. At first, I didn't feel it is necessary. But in
      #15, TOMOYO uses standard doubly linked list and getting close to be able
      to know whether there is a reader process or not. Also, I changed to use
      kmalloc(GFP_KERNEL)/kfree() to realize the key point (1) in this patch.
      TOMOYO is almost ready to have GC support.

This patch is very large, so I'll create splitted patches if you need.
Thank you for your time.

------- End of Forwarded Message

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH] TOMOYO: Add garbage collector support. (v2)
  2009-05-25  0:37                       ` Tetsuo Handa
@ 2009-05-25  0:39                         ` Tetsuo Handa
  2009-05-25  0:41                           ` Tetsuo Handa
  0 siblings, 1 reply; 34+ messages in thread
From: Tetsuo Handa @ 2009-05-25  0:39 UTC (permalink / raw)
  To: jmorris; +Cc: linux-security-module, linux-kernel

------- Forwarded Message
 From: "Serge E. Hallyn" <serue@us.ibm.com>
 To: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
 Cc: haradats@nttdata.co.jp, takedakn@nttdata.co.jp,James Morris <jmorris@namei.org>
 Subject: Re: [PATCH] TOMOYO: Add garbage collector support. (v2)
 Date: Thu, 21 May 2009 17:23:13 -0500

Quoting Tetsuo Handa (penguin-kernel@I-love.SAKURA.ne.jp):
> The key points are:
> 
>   (1) Should TOMOYO avoid sleeping operations inside a semaphore?

Seems like an obvious win.

>   (2) Should TOMOYO have GC support?

Well if your only audience is meant to be tiny embedded systems which
will never update policy, then heck maybe not.  But it certainly is
weird not to.

However, the way you went about it here is weird too.  The big
cookie list that pins items, instead of refcounts, is very un-linuxy.
Is there a reason why you can't use more of a read-copy-update
approach?  Keep a refcount on the objects, get rid of ->is_deleted,
remove the objects from their list instead of setting is_deleted
(so that after one rcu cycle no new readers can come in and increment
the refcount), wait an rcu cycle, and then free if refcount is 0?
See linux-2.6/Documentation/RCU/* for documentation.

In particular, the
	list_for_each over tomoyo_pattenrs, domains, whatever {
		tomoyo_used_by_cookie
where tomoyo_used_by_cookie then walks every cookie, meaning every
tomoyo object, seems hugely expensive to me.  I know it's only at
policy load, but...

So anyway, I'm torn between not asking for a huge effort to
fundamentally change the way you do your memory management, vs.
making the Tomoyo code a lot more linux-y, and therefore a lot
easier for other kernel people to read/review/maintain/update.

So yes, you might be able to get more review of your patch
if you split it up into:

	1. move allocations outside of semaphore
	2. add proper refcounting
	3. get rid of ->is_deleted

Hah, as I type that, I finally realize why your code fell out this
way :)  You needed is_deleted to keep invalid domains from being
used, but didn't want to properly free them bc you didn't have GC.
So yes, get rid of ->is_deleted, add refcounting, maybe use rcu
rules to clearly distinguish objects which can no longer be
accessed by anyone else, then free such objects.

A pair of more general things I noticed:

1. tomoyo_real_domain: just return task_cred_xxx(task, security)  ?

2. tomoyo_init() after your patch: you don't catch -ENOMEM?

thanks,
-serge

PS - I'll be out of touch for a few days after tonight.

------- End of Forwarded Message

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH] TOMOYO: Add garbage collector support. (v2)
  2009-05-25  0:39                         ` Tetsuo Handa
@ 2009-05-25  0:41                           ` Tetsuo Handa
  2009-05-27  0:16                             ` Paul E. McKenney
  2009-06-01 13:27                             ` Tetsuo Handa
  0 siblings, 2 replies; 34+ messages in thread
From: Tetsuo Handa @ 2009-05-25  0:41 UTC (permalink / raw)
  To: jmorris; +Cc: linux-security-module, linux-kernel

------- Forwarded Message
 From: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
 To: serue@us.ibm.com, jmorris@namei.org
 Cc: haradats@nttdata.co.jp, takedakn@nttdata.co.jp
 Subject: Re: [PATCH] TOMOYO: Add garbage collector support. (v2)
 Date: Sat, 23 May 2009 11:05:24 +0900

Thank you for reviewing.

Serge E. Hallyn wrote:
> So yes, you might be able to get more review of your patch
> if you split it up into:
> 
> 	1. move allocations outside of semaphore
> 	2. add proper refcounting
> 	3. get rid of ->is_deleted

I'm ready to post part (1).

 security/tomoyo/common.c   |   80 ++++++---------------
 security/tomoyo/common.h   |    2 
 security/tomoyo/domain.c   |   97 ++++++++++++-------------
 security/tomoyo/file.c     |  133 ++++++++++++++++++-----------------
 security/tomoyo/realpath.c |  169 ++++++++++++++-------------------------------
 security/tomoyo/realpath.h |    7 -
 6 files changed, 200 insertions(+), 288 deletions(-)

http://svn.sourceforge.jp/cgi-bin/viewcvs.cgi/trunk/2.2.x/tomoyo-lsm/patches/tomoyo-move-sleeping-operations-to-outside-semaphore.patch?view=markup&revision=2579&root=tomoyo

But I think I won't get rid of ->is_deleted. Reasons are shown below.

> However, the way you went about it here is weird too.  The big
> cookie list that pins items, instead of refcounts, is very un-linuxy.
> Is there a reason why you can't use more of a read-copy-update
> approach?  Keep a refcount on the objects, get rid of ->is_deleted,
> remove the objects from their list instead of setting is_deleted
> (so that after one rcu cycle no new readers can come in and increment
> the refcount), wait an rcu cycle, and then free if refcount is 0?

All items are linked using "struct list_head".
TOMOYO uses "struct tomoyo_io_buffer" with three "struct list_head" members
named ->read_var1 / ->read_var2 / ->write_var1 for handling read()/write() via
securityfs interface. These members act as cookies.

Within a single read() request, it is possible to protect the list by using
down_read(). But an administrator won't read out all items in a single read()
request. Therefore, TOMOYO stores the item which is scheduled to be accessed on
next read() request into ->read_var1 and ->read_var2 .

Similar situation for write() request. An administrator won't write all items
in a single write() request. Therefore, TOMOYO stores the item which is
accessed on next write() request into ->write_var1 .

The ->read_var1 / ->read_var2 / ->write_var1 act as cookies.

Yes, I can add a refcounter to all items which is only used for remembering
whether an item is stored in ->read_var1 / ->read_var2 / ->write_var1 or not.

When the item which ->read_var1 / ->read_var2 / ->write_var1 refer changes,
we have to decrement the refcount of the object pointed by old ->read_var1 /
->read_var2 / ->write_var1 and increment the refcount of the object pointed by
new ->read_var1 / ->read_var2 / ->write_var1 before releasing the lock.

I pinned the address of "struct list_head" into the cookie list so that I don't
need to increment/decrement of an item's refcounter while guaranteeing that the
item pointed by the cookie list shall remain valid after up_read()/up_write().

> where tomoyo_used_by_cookie then walks every cookie, meaning every
> tomoyo object, seems hugely expensive to me.  I know it's only at
> policy load, but...
The cookie list approach will save memory compared to the refcounter approach
because the number of cookies in the cookie list will be smaller than
the number of items in all lists except the cookie list.

Even if we defer releasing memory of a deleted item, we can't remove an
item from the list when an administrator deleted the item.
Removing from the list (i.e. list_del()) will modify ->next and ->prev pointer
of the item. If the item was scheduled to be accessed on next read() request,
TOMOYO will crash by dereferencing ->next pointer of the item.
Use of RCU does not help here because we need to keep the item valid as long as
the item is referred by ->read_var1 or ->read_var2 or ->write_var1 .

The ->is_deleted flag is needed for skipping an item in read() request
because TOMOYO can't modify ->next and ->prev pointer of an item when that item
is scheduled to be accessed on next read() request.

My opinion is that the refcounter approach might replace the cookie list
approach, but the refcounter approach can't get rid of ->is_deleted flag.

> >   (2) Should TOMOYO have GC support?
> 
> Well if your only audience is meant to be tiny embedded systems which
> will never update policy, then heck maybe not.  But it certainly is
> weird not to.

The non-LSM version of TOMOYO is "GC support free" but saves a lot of memory
by using "singly linked list", "read lock free", "refcounter free" approach.

Maybe we should add a refcounter to all items and avoid the cookie list.
In that case, we can allow users to determine via the kernel config whether
TOMOYO supports GC or not. If GC support is not chosen via the kernel config,
TOMOYO can save memory by using "singly linked list", "read lock free",
"refcounter free" approach.

------- End of Forwarded Message

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH] TOMOYO: Add garbage collector support. (v2)
  2009-05-25  0:41                           ` Tetsuo Handa
@ 2009-05-27  0:16                             ` Paul E. McKenney
  2009-05-27  1:25                               ` Tetsuo Handa
  2009-06-01 13:27                             ` Tetsuo Handa
  1 sibling, 1 reply; 34+ messages in thread
From: Paul E. McKenney @ 2009-05-27  0:16 UTC (permalink / raw)
  To: Tetsuo Handa; +Cc: jmorris, linux-security-module, linux-kernel

On Mon, May 25, 2009 at 09:41:31AM +0900, Tetsuo Handa wrote:
> ------- Forwarded Message
>  From: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
>  To: serue@us.ibm.com, jmorris@namei.org
>  Cc: haradats@nttdata.co.jp, takedakn@nttdata.co.jp
>  Subject: Re: [PATCH] TOMOYO: Add garbage collector support. (v2)
>  Date: Sat, 23 May 2009 11:05:24 +0900
> 
> Thank you for reviewing.
> 
> Serge E. Hallyn wrote:
> > So yes, you might be able to get more review of your patch
> > if you split it up into:
> > 
> > 	1. move allocations outside of semaphore
> > 	2. add proper refcounting
> > 	3. get rid of ->is_deleted
> 
> I'm ready to post part (1).
> 
>  security/tomoyo/common.c   |   80 ++++++---------------
>  security/tomoyo/common.h   |    2 
>  security/tomoyo/domain.c   |   97 ++++++++++++-------------
>  security/tomoyo/file.c     |  133 ++++++++++++++++++-----------------
>  security/tomoyo/realpath.c |  169 ++++++++++++++-------------------------------
>  security/tomoyo/realpath.h |    7 -
>  6 files changed, 200 insertions(+), 288 deletions(-)
> 
> http://svn.sourceforge.jp/cgi-bin/viewcvs.cgi/trunk/2.2.x/tomoyo-lsm/patches/tomoyo-move-sleeping-operations-to-outside-semaphore.patch?view=markup&revision=2579&root=tomoyo
> 
> But I think I won't get rid of ->is_deleted. Reasons are shown below.
> 
> > However, the way you went about it here is weird too.  The big
> > cookie list that pins items, instead of refcounts, is very un-linuxy.
> > Is there a reason why you can't use more of a read-copy-update
> > approach?  Keep a refcount on the objects, get rid of ->is_deleted,
> > remove the objects from their list instead of setting is_deleted
> > (so that after one rcu cycle no new readers can come in and increment
> > the refcount), wait an rcu cycle, and then free if refcount is 0?
> 
> All items are linked using "struct list_head".
> TOMOYO uses "struct tomoyo_io_buffer" with three "struct list_head" members
> named ->read_var1 / ->read_var2 / ->write_var1 for handling read()/write() via
> securityfs interface. These members act as cookies.
> 
> Within a single read() request, it is possible to protect the list by using
> down_read(). But an administrator won't read out all items in a single read()
> request. Therefore, TOMOYO stores the item which is scheduled to be accessed on
> next read() request into ->read_var1 and ->read_var2 .
> 
> Similar situation for write() request. An administrator won't write all items
> in a single write() request. Therefore, TOMOYO stores the item which is
> accessed on next write() request into ->write_var1 .
> 
> The ->read_var1 / ->read_var2 / ->write_var1 act as cookies.
> 
> Yes, I can add a refcounter to all items which is only used for remembering
> whether an item is stored in ->read_var1 / ->read_var2 / ->write_var1 or not.
> 
> When the item which ->read_var1 / ->read_var2 / ->write_var1 refer changes,
> we have to decrement the refcount of the object pointed by old ->read_var1 /
> ->read_var2 / ->write_var1 and increment the refcount of the object pointed by
> new ->read_var1 / ->read_var2 / ->write_var1 before releasing the lock.
> 
> I pinned the address of "struct list_head" into the cookie list so that I don't
> need to increment/decrement of an item's refcounter while guaranteeing that the
> item pointed by the cookie list shall remain valid after up_read()/up_write().
> 
> > where tomoyo_used_by_cookie then walks every cookie, meaning every
> > tomoyo object, seems hugely expensive to me.  I know it's only at
> > policy load, but...
> The cookie list approach will save memory compared to the refcounter approach
> because the number of cookies in the cookie list will be smaller than
> the number of items in all lists except the cookie list.
> 
> Even if we defer releasing memory of a deleted item, we can't remove an
> item from the list when an administrator deleted the item.
> Removing from the list (i.e. list_del()) will modify ->next and ->prev pointer
> of the item. If the item was scheduled to be accessed on next read() request,
> TOMOYO will crash by dereferencing ->next pointer of the item.

The list_del_rcu() primitive is designed for removing elements from
lists that have concurrent readers, and it therefore avoids changing the
->next pointer.  That said, I don't immediately see whether or not there
is some other reason you need to keep it on the list.  And do you need
the ->prev pointer to stay valid?  If not, you might be able to use it
in place of the ->is_deleted flag.

> Use of RCU does not help here because we need to keep the item valid as long as
> the item is referred by ->read_var1 or ->read_var2 or ->write_var1 .

You would indeed need some way of tracking those references.  One
approach is to make the RCU callback check to see if any of them
reference the to-be-deleted object, reposting itself if so.  This
approach assumes that such a reference is short-lived, of course.

If the ->read_var1 and other references are long-lived, could you
post an RCU callback when the last such reference was removed?

> The ->is_deleted flag is needed for skipping an item in read() request
> because TOMOYO can't modify ->next and ->prev pointer of an item when that item
> is scheduled to be accessed on next read() request.
> 
> My opinion is that the refcounter approach might replace the cookie list
> approach, but the refcounter approach can't get rid of ->is_deleted flag.

Some RCU algorithms do use something similar to the ->is_deleted flag.

							Thanx, Paul

> > >   (2) Should TOMOYO have GC support?
> > 
> > Well if your only audience is meant to be tiny embedded systems which
> > will never update policy, then heck maybe not.  But it certainly is
> > weird not to.
> 
> The non-LSM version of TOMOYO is "GC support free" but saves a lot of memory
> by using "singly linked list", "read lock free", "refcounter free" approach.
> 
> Maybe we should add a refcounter to all items and avoid the cookie list.
> In that case, we can allow users to determine via the kernel config whether
> TOMOYO supports GC or not. If GC support is not chosen via the kernel config,
> TOMOYO can save memory by using "singly linked list", "read lock free",
> "refcounter free" approach.
> 
> ------- End of Forwarded Message
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH] TOMOYO: Add garbage collector support. (v2)
  2009-05-27  0:16                             ` Paul E. McKenney
@ 2009-05-27  1:25                               ` Tetsuo Handa
  2009-05-27  4:12                                 ` Paul E. McKenney
  0 siblings, 1 reply; 34+ messages in thread
From: Tetsuo Handa @ 2009-05-27  1:25 UTC (permalink / raw)
  To: paulmck; +Cc: jmorris, linux-security-module, linux-kernel

Hello.

Paul E. McKenney wrote:
> The list_del_rcu() primitive is designed for removing elements from
> lists that have concurrent readers, and it therefore avoids changing the
> ->next pointer.  That said, I don't immediately see whether or not there
> is some other reason you need to keep it on the list.  And do you need
> the ->prev pointer to stay valid?  If not, you might be able to use it
> in place of the ->is_deleted flag.

I don't need ->prev pointer.

> > Use of RCU does not help here because we need to keep the item valid as long as
> > the item is referred by ->read_var1 or ->read_var2 or ->write_var1 .
> 
> You would indeed need some way of tracking those references.  One
> approach is to make the RCU callback check to see if any of them
> reference the to-be-deleted object, reposting itself if so.  This
> approach assumes that such a reference is short-lived, of course.
> 
> If the ->read_var1 and other references are long-lived, could you
> post an RCU callback when the last such reference was removed?

The reference stored in ->read_var1 / ->read_var2 / ->write_var1 are long-lived
(it varies from less than one second to more than many hours).

Well, it's time for me to read all Documentation/RCU/* .

Thanks.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH] TOMOYO: Add garbage collector support. (v2)
  2009-05-27  1:25                               ` Tetsuo Handa
@ 2009-05-27  4:12                                 ` Paul E. McKenney
  0 siblings, 0 replies; 34+ messages in thread
From: Paul E. McKenney @ 2009-05-27  4:12 UTC (permalink / raw)
  To: Tetsuo Handa; +Cc: jmorris, linux-security-module, linux-kernel

On Wed, May 27, 2009 at 10:25:28AM +0900, Tetsuo Handa wrote:
> Hello.
> 
> Paul E. McKenney wrote:
> > The list_del_rcu() primitive is designed for removing elements from
> > lists that have concurrent readers, and it therefore avoids changing the
> > ->next pointer.  That said, I don't immediately see whether or not there
> > is some other reason you need to keep it on the list.  And do you need
> > the ->prev pointer to stay valid?  If not, you might be able to use it
> > in place of the ->is_deleted flag.
> 
> I don't need ->prev pointer.
> 
> > > Use of RCU does not help here because we need to keep the item valid as long as
> > > the item is referred by ->read_var1 or ->read_var2 or ->write_var1 .
> > 
> > You would indeed need some way of tracking those references.  One
> > approach is to make the RCU callback check to see if any of them
> > reference the to-be-deleted object, reposting itself if so.  This
> > approach assumes that such a reference is short-lived, of course.
> > 
> > If the ->read_var1 and other references are long-lived, could you
> > post an RCU callback when the last such reference was removed?
> 
> The reference stored in ->read_var1 / ->read_var2 / ->write_var1 are long-lived
> (it varies from less than one second to more than many hours).

Then one approach would be to check the ->is_deleted flag (or the
->prev pointer) when removing one of the ->read_varN references.
If the flag is set, and if no other ->read_varN references the same
object, post an RCU callback to clean it up.

Of course, when removing the object to start with, you could check
the references, and if none of them referenced the object, you could
post the callback immediately.

Or something similar.

> Well, it's time for me to read all Documentation/RCU/* .

I would also recommend the three-part LWN series as a starting point:

#       http://lwn.net/Articles/262464/ (What is RCU, Fundamentally?)
#       http://lwn.net/Articles/263130/ (What is RCU's Usage?)
#       http://lwn.net/Articles/264090/ (What is RCU's API?)

						Thanx, Paul

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH] TOMOYO: Add garbage collector support. (v2)
  2009-05-25  0:41                           ` Tetsuo Handa
  2009-05-27  0:16                             ` Paul E. McKenney
@ 2009-06-01 13:27                             ` Tetsuo Handa
  2009-06-02  0:11                               ` Serge E. Hallyn
  1 sibling, 1 reply; 34+ messages in thread
From: Tetsuo Handa @ 2009-06-01 13:27 UTC (permalink / raw)
  To: serue; +Cc: linux-security-module, linux-kernel

Hello.

Serge E. Hallyn wrote:
> So yes, you might be able to get more review of your patch
> if you split it up into:
> 
> 	1. move allocations outside of semaphore
> 	2. add proper refcounting
> 	3. get rid of ->is_deleted

I'm ready to post part (1) and part (2).
But I'm not sure whether part (3) is worth to implement or not.

If we don't use is_deleted flag, we will need two "struct list_head"s,
one is for readers and writers, the other is for GC.

struct something {
	struct {
		struct list_head list;
		atomic_t users;
	} entry;
	int data;
	bool is_deleted;
} *p;

If we remove p from the list using list_del() (or list_del_rcu()) instead of
setting p->is_deleted to true, we have to somehow remember the element pointed
by p so that that element is reachable from the GC's list.
We can't wait for p->entry.users to become 0 inside writer function (which is
called only when modifying lists). Only GC function (which is called
repeatedly) can check whether p->entry.users == 0 or not because the element
pointed by p is long-lived. We need to remember the location of the element
pointed by p .

We can allocate memory when adding p to GC's list, but allocating memory at
list_del() (or list_del_rcu()) time could fail. It is not a good thing that
removing an element from the reader's list fails because of -ENOMEM. We already
have a way (i.e. is_deleted flag) to avoid -ENOMEM.

We can add another "struct list_head" to each element which is used by GC.
But that approach consumes more memory than is_deleted flag.

Regards.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH] TOMOYO: Add garbage collector support. (v2)
  2009-06-01 13:27                             ` Tetsuo Handa
@ 2009-06-02  0:11                               ` Serge E. Hallyn
  2009-06-02  0:30                                 ` Tetsuo Handa
  0 siblings, 1 reply; 34+ messages in thread
From: Serge E. Hallyn @ 2009-06-02  0:11 UTC (permalink / raw)
  To: Tetsuo Handa; +Cc: serue, linux-security-module, linux-kernel

Quoting Tetsuo Handa (penguin-kernel@I-love.SAKURA.ne.jp):
> Hello.
> 
> Serge E. Hallyn wrote:
> > So yes, you might be able to get more review of your patch
> > if you split it up into:
> > 
> > 	1. move allocations outside of semaphore
> > 	2. add proper refcounting
> > 	3. get rid of ->is_deleted
> 
> I'm ready to post part (1) and part (2).
> But I'm not sure whether part (3) is worth to implement or not.
>
> If we don't use is_deleted flag, we will need two "struct list_head"s,
> one is for readers and writers, the other is for GC.
> 
> struct something {
> 	struct {
> 		struct list_head list;
> 		atomic_t users;
> 	} entry;
> 	int data;
> 	bool is_deleted;
> } *p;
> 
> If we remove p from the list using list_del() (or list_del_rcu()) instead of
> setting p->is_deleted to true, we have to somehow remember the element pointed
> by p so that that element is reachable from the GC's list.
> We can't wait for p->entry.users to become 0 inside writer function (which is
> called only when modifying lists). Only GC function (which is called
> repeatedly) can check whether p->entry.users == 0 or not because the element
> pointed by p is long-lived. We need to remember the location of the element
> pointed by p .

?

Can't you just move the deleted item from the live list to some dead
list, using the same ->list list_head?

> We can allocate memory when adding p to GC's list, but allocating memory at
> list_del() (or list_del_rcu()) time could fail. It is not a good thing that
> removing an element from the reader's list fails because of -ENOMEM. We already
> have a way (i.e. is_deleted flag) to avoid -ENOMEM.
> 
> We can add another "struct list_head" to each element which is used by GC.
> But that approach consumes more memory than is_deleted flag.

?

See above.

-serge

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH] TOMOYO: Add garbage collector support. (v2)
  2009-06-02  0:11                               ` Serge E. Hallyn
@ 2009-06-02  0:30                                 ` Tetsuo Handa
  2009-06-02  1:03                                   ` Serge E. Hallyn
  0 siblings, 1 reply; 34+ messages in thread
From: Tetsuo Handa @ 2009-06-02  0:30 UTC (permalink / raw)
  To: serge; +Cc: serue, linux-security-module, linux-kernel

Serge E. Hallyn wrote:
> Can't you just move the deleted item from the live list to some dead
> list, using the same ->list list_head?

I think I can't. If we do list_add(&p->entry.list, &dead_list) after
list_del_rcu(&p->entry.list) when p->entry.users != 0, p->entry.list.next will
point to an element on dead list. And reader will no longer be able to resume
travarsal on the live list.

I don't want the item be deleted from the live list as long as there are
readers (i.e. p->entry.users != 0).

If we use different ->list list_head, reader will be able to resume travarsal
on the live list. (But will use more memory than ->is_deleted.)

struct something {
	struct {
		struct list_head list_for_live_list;
		atomic_t users;
	} entry;
	struct list_head list_for_dead_list;
	int data;
} *p;

Regards.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH] TOMOYO: Add garbage collector support. (v2)
  2009-06-02  0:30                                 ` Tetsuo Handa
@ 2009-06-02  1:03                                   ` Serge E. Hallyn
  2009-06-02  1:16                                     ` Tetsuo Handa
  0 siblings, 1 reply; 34+ messages in thread
From: Serge E. Hallyn @ 2009-06-02  1:03 UTC (permalink / raw)
  To: Tetsuo Handa; +Cc: serue, linux-security-module, linux-kernel

Quoting Tetsuo Handa (penguin-kernel@i-love.sakura.ne.jp):
> Serge E. Hallyn wrote:
> > Can't you just move the deleted item from the live list to some dead
> > list, using the same ->list list_head?
> 
> I think I can't. If we do list_add(&p->entry.list, &dead_list) after
> list_del_rcu(&p->entry.list) when p->entry.users != 0, p->entry.list.next will
> point to an element on dead list. And reader will no longer be able to resume
> travarsal on the live list.

Use rcu?  Take your spinlock, take entry off the list, wait an rcu cycle,
then move to the dead_list.

All readers should walk the list under rcu_read_lock, so if the manage
to reach ->entry, then entry.list->next will be a valid entry on the live
list until the next rcu cycle.

BTW I'm not telling you have to do this, so if you just don't want to, then
just say so.  But so long as you come back to me with technical reasons
why you can't, then I take it you're interested in a technical solution :)
and can't help but respond...

-serge

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH] TOMOYO: Add garbage collector support. (v2)
  2009-06-02  1:03                                   ` Serge E. Hallyn
@ 2009-06-02  1:16                                     ` Tetsuo Handa
  2009-06-02  3:35                                       ` Paul E. McKenney
  0 siblings, 1 reply; 34+ messages in thread
From: Tetsuo Handa @ 2009-06-02  1:16 UTC (permalink / raw)
  To: serge; +Cc: serue, linux-security-module, linux-kernel

Serge E. Hallyn wrote:
> All readers should walk the list under rcu_read_lock, so if the manage
> to reach ->entry, then entry.list->next will be a valid entry on the live
> list until the next rcu cycle.

I have to tell you one thing.
Reader traverses the list via read(2) system call.
It means that reader can't read all elements in the list within a single
read(2) system call.
Thus, reader grabs a reference on an element (i.e. p->entry.users) before
leaving reader section and drops that reference after entering reader section.

Yes, it would be possible for readers to walk the list under rcu_read_lock(),
but it is not sufficient for GC to simply call synchronize_rcu(). GC has to
wait for p->entry.users to become 0 before modifying p->entry.list.next .

> BTW I'm not telling you have to do this, so if you just don't want to, then
> just say so.  But so long as you come back to me with technical reasons
> why you can't, then I take it you're interested in a technical solution :)
> and can't help but respond...

I see. I'll post only (1) and (2).

Thank you for your suggestion and time.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH] TOMOYO: Add garbage collector support. (v2)
  2009-06-02  1:16                                     ` Tetsuo Handa
@ 2009-06-02  3:35                                       ` Paul E. McKenney
  0 siblings, 0 replies; 34+ messages in thread
From: Paul E. McKenney @ 2009-06-02  3:35 UTC (permalink / raw)
  To: Tetsuo Handa; +Cc: serge, serue, linux-security-module, linux-kernel

On Tue, Jun 02, 2009 at 10:16:54AM +0900, Tetsuo Handa wrote:
> Serge E. Hallyn wrote:
> > All readers should walk the list under rcu_read_lock, so if the manage
> > to reach ->entry, then entry.list->next will be a valid entry on the live
> > list until the next rcu cycle.
> 
> I have to tell you one thing.
> Reader traverses the list via read(2) system call.
> It means that reader can't read all elements in the list within a single
> read(2) system call.
> Thus, reader grabs a reference on an element (i.e. p->entry.users) before
> leaving reader section and drops that reference after entering reader section.
> 
> Yes, it would be possible for readers to walk the list under rcu_read_lock(),
> but it is not sufficient for GC to simply call synchronize_rcu(). GC has to
> wait for p->entry.users to become 0 before modifying p->entry.list.next .

The usual approach would be for the code that causes p->entry.users
to become zero to do the list_del_rcu() and then pass the entry to
call_rcu().  Or execute synchronize_rcu() if blocking is permissible.

Of course, it is necessary to handle the race where one task decrements
the counter to zero while another increments it back up to 1.  One way to
handle this is to use atomic_inc_not_zero() when acquiring a reference,
thus refusing to acquire the reference if the count is already zero.
But your GC would need to handle this same race condition, so whatever
you were doing in that case should work here as well.

							Thanx, Paul

> > BTW I'm not telling you have to do this, so if you just don't want to, then
> > just say so.  But so long as you come back to me with technical reasons
> > why you can't, then I take it you're interested in a technical solution :)
> > and can't help but respond...
> 
> I see. I'll post only (1) and (2).
> 
> Thank you for your suggestion and time.
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

^ permalink raw reply	[flat|nested] 34+ messages in thread

end of thread, other threads:[~2009-06-02  3:35 UTC | newest]

Thread overview: 34+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-04-08 13:31 [TOMOYO 0/2] Final patches for kenrel 2.6.30 Tetsuo Handa
2009-04-08 13:31 ` [TOMOYO 1/2] tomoyo: add Documentation/tomoyo.txt Tetsuo Handa
2009-04-10 12:26   ` Peter Dolding
2009-04-10 17:10   ` Pavel Machek
2009-04-13  2:04     ` Tetsuo Handa
2009-04-29 13:13       ` Pavel Machek
2009-05-01 10:24       ` Pavel Machek
2009-05-01 13:07         ` Tetsuo Handa
2009-05-03 21:56           ` Pavel Machek
2009-05-04  6:24             ` Tetsuo Handa
2009-05-06 12:16               ` Tetsuo Handa
2009-05-07 11:42                 ` [TOMOYO] Add garbage collector support Tetsuo Handa
2009-05-08  1:43                   ` James Morris
2009-05-08  2:10                     ` Tetsuo Handa
2009-05-08  8:26                       ` James Morris
2009-05-08  9:22                         ` Tetsuo Handa
2009-05-08  9:32                   ` Pavel Machek
2009-05-14 12:08                 ` [PATCH] TOMOYO: Add garbage collector support. (v2) Tetsuo Handa
2009-05-15  1:49                   ` James Morris
2009-05-16 12:07                     ` Tetsuo Handa
2009-05-25  0:37                       ` Tetsuo Handa
2009-05-25  0:39                         ` Tetsuo Handa
2009-05-25  0:41                           ` Tetsuo Handa
2009-05-27  0:16                             ` Paul E. McKenney
2009-05-27  1:25                               ` Tetsuo Handa
2009-05-27  4:12                                 ` Paul E. McKenney
2009-06-01 13:27                             ` Tetsuo Handa
2009-06-02  0:11                               ` Serge E. Hallyn
2009-06-02  0:30                                 ` Tetsuo Handa
2009-06-02  1:03                                   ` Serge E. Hallyn
2009-06-02  1:16                                     ` Tetsuo Handa
2009-06-02  3:35                                       ` Paul E. McKenney
2009-04-08 13:31 ` [TOMOYO 2/2] Hello Tetsuo Handa
2009-04-10 11:55   ` Tetsuo Handa

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox