linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [AppArmor 00/41] AppArmor security module overview
@ 2007-04-12  9:08 jjohansen
  2007-04-12  9:08 ` [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook jjohansen
                   ` (43 more replies)
  0 siblings, 44 replies; 187+ messages in thread
From: jjohansen @ 2007-04-12  9:08 UTC (permalink / raw)
  To: linux-kernel; +Cc: linux-security-module, linux-fsdevel, chrisw

This post contains patches to include the AppArmor application security
framework, with request for inclusion.

The patch series consists of four areas:

 (1) Pass struct vfsmount through to LSM hooks.

     Tony Jones has posted almost all of these patches here before on
     February 5; the feedback given has been incorporated.

 (2) Fixes and improvements to d_path:

     (a) make it unambiguous and exclude unreachable paths from
         /proc/mounts,

     (b) make its result consistent in the face of remounts,

     (c) introduce d_namespace_path(), a variant of d_path that goes up
         to the namespace root instead of the chroot.

     Part (a) has been in the -mm tree for more than a month; this
     series includes a copy of the -mm patch. Parts (b) and (c)
     shouldn't be too controversial.

 (3) Be able to distinguish file descriptor access from access by name
     in LSM hooks.

     Applications expect different behavior from file descriptor
     accesses and accesses by name in some cases. We need to pass this
     information down the LSM hooks to allow AppArmor to tell which is
     which.

 (4) The AppArmor LSM itself.

     (See below.)

A tarball of the kernel patches, base user-space utilities, example
profiles, and technical documentation (including a walk-through) are
available at:

  http://forgeftp.novell.com//apparmor/LKML_Submission-April_07/


The rest of this introduction gives a brief overview of AppArmor's
overall design. We will try to address the concerns people had when
AppArmor was previously posted here in April 06 in a follow-up post.


AppArmor's Overall Design
=========================

AppArmor protects systems from vulnerable software by confining
processes, giving them "least privilege" access to the system's
resources: with least privilege, processes are allowed exactly what they
need, nothing more, and nothing less. Systems are thus protected from
bugs in applications that would lead to privilege escalation, such as
remote system access because of a buffer overflow in a web server, etc.

AppArmor does this by defining application profiles which list allowed
accesses, and assigning those profiles to processes. AppArmor does *not*
require the user to confine all processes on the system.  Rather, you
need to provide AppArmor profiles for every process that is potentially
subject to manipulation by the attacker. For instance, to defend against
network attack, confine all process that access the network.

The corollary to this is that attacks against AppArmor that start with
"assume some unconfined process does ..." are outside the AppArmor
threat model. Any process that might do something malicious to an
AppArmor system should be confined by an AppArmor profile.

The kernel manages many different kinds of resources.  AppArmor
currently controls access to two key resources among them: files, and
POSIX Capabilities.  (Additional protection for things like rlimits,
interprocess communication, and network access are being worked on, and
are expected to become available in a future version.)


File Access Control
-------------------

Application profiles control file access by pathname: each profile
contains a list of fully qualified pathnames (potentially containing
globbing) and associated access modes: read (r), write (w), different
kinds of execute (ix, Px, px, Ux, ux), create hard-link (l), and memory
map for execution (m).

For example, the following two rules permit read access to any file
below /srv/www/htdocs/**.html, and memory map for execution (m), execute
inheriting the current profile (ix), and read (r) access to
/usr/sbin/suexec2:

    /srv/www/htdocs/**.html r,
    /usr/sbin/suexec2 mixr,


POSIX Capabilities
------------------

Application profiles enumerate the POSIX capabilites that a process may
use. (A process must have a capability both in its effective
capabilities set and in its profile in order to use it. See the
capabilities(7) manual page for details on capabilities.)

For example, the following rule allows processes to chroot(2):

    capability sys_chroot,


An Example Profile
------------------

Here is an example profile for ntpd:

    /usr/sbin/ntpd {
      #include <abstractions/base>
      #include <abstractions/nameservice>

      capability ipc_lock,
      capability net_bind_service,
      capability setgid,
      capability setuid,
      capability sys_chroot,
      capability sys_resource,
      capability sys_time,

      /drift/ntp.drift rwl,
      /drift/ntp.drift.TEMP rwl,
      /etc/ntp.conf r,
      /etc/ntp/drift* rwl,
      /etc/ntp/keys r,
      /etc/ntp/step-tickers r,
      /tmp/ntp* rwl,
      /usr/sbin/ntpd rmix,
      /var/lib/ntp/etc/ntp.conf.iburst  r,
      /var/lib/ntp/drift rwl,
      /var/lib/ntp/drift.TEMP rwl,
      /var/lib/ntp/drift/ntp.drift r,
      /var/lib/ntp/var/run/ntp/ntpd.pid w,
      /var/log/ntp w,
      /var/log/ntp.log w,
      /var/run/ntpd.pid w,
    }

Briefly, the /usr/sbin/ntpd in line 1 tells AppArmor to use this profile
for /usr/sbin/ntpd.  The include lines pull in some predefined
abstractions containing frequently used access patterns which allow to
keep profiles short, and the capability and file access rules have been
explained above.

Explaining the AppArmor design in detail would take by far too much
space here, so let me refer you to the technical documentation for that.
Included is a low-level walk-through of the system and basic tools, and
some examples.  The manual pages included in the apparmor-parser package
are worth a read as well.

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

* [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-04-12  9:08 [AppArmor 00/41] AppArmor security module overview jjohansen
@ 2007-04-12  9:08 ` jjohansen
  2007-04-12 10:06   ` Christoph Hellwig
  2007-04-12 10:12   ` [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook Al Viro
  2007-04-12  9:08 ` [AppArmor 02/41] Remove redundant check from proc_setattr() jjohansen
                   ` (42 subsequent siblings)
  43 siblings, 2 replies; 187+ messages in thread
From: jjohansen @ 2007-04-12  9:08 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, linux-fsdevel, chrisw, Tony Jones,
	Andreas Gruenbacher, John Johansen

[-- Attachment #1: security-create.diff --]
[-- Type: text/plain, Size: 3186 bytes --]

This is needed for computing pathnames in the AppArmor LSM.

Signed-off-by: Tony Jones <tonyj@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>

---
 fs/namei.c               |    2 +-
 include/linux/security.h |    9 ++++++---
 security/dummy.c         |    2 +-
 security/selinux/hooks.c |    3 ++-
 4 files changed, 10 insertions(+), 6 deletions(-)

--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1503,7 +1503,7 @@ int vfs_create(struct inode *dir, struct
 		return -EACCES;	/* shouldn't it be ENOSYS? */
 	mode &= S_IALLUGO;
 	mode |= S_IFREG;
-	error = security_inode_create(dir, dentry, mode);
+	error = security_inode_create(dir, dentry, nd ? nd->mnt : NULL, mode);
 	if (error)
 		return error;
 	DQUOT_INIT(dir);
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -283,6 +283,7 @@ struct request_sock;
  *	Check permission to create a regular file.
  *	@dir contains inode structure of the parent of the new file.
  *	@dentry contains the dentry structure for the file to be created.
+ *	@mnt is the vfsmount corresponding to @dentry (may be NULL).
  *	@mode contains the file mode of the file to be created.
  *	Return 0 if permission is granted.
  * @inode_link:
@@ -1204,8 +1205,8 @@ struct security_operations {
 	void (*inode_free_security) (struct inode *inode);
 	int (*inode_init_security) (struct inode *inode, struct inode *dir,
 				    char **name, void **value, size_t *len);
-	int (*inode_create) (struct inode *dir,
-	                     struct dentry *dentry, int mode);
+	int (*inode_create) (struct inode *dir, struct dentry *dentry,
+			     struct vfsmount *mnt, int mode);
 	int (*inode_link) (struct dentry *old_dentry,
 	                   struct inode *dir, struct dentry *new_dentry);
 	int (*inode_unlink) (struct inode *dir, struct dentry *dentry);
@@ -1611,11 +1612,12 @@ static inline int security_inode_init_se
 	
 static inline int security_inode_create (struct inode *dir,
 					 struct dentry *dentry,
+					 struct vfsmount *mnt,
 					 int mode)
 {
 	if (unlikely (IS_PRIVATE (dir)))
 		return 0;
-	return security_ops->inode_create (dir, dentry, mode);
+	return security_ops->inode_create (dir, dentry, mnt, mode);
 }
 
 static inline int security_inode_link (struct dentry *old_dentry,
@@ -2338,6 +2340,7 @@ static inline int security_inode_init_se
 	
 static inline int security_inode_create (struct inode *dir,
 					 struct dentry *dentry,
+					 struct vfsmount *mnt,
 					 int mode)
 {
 	return 0;
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -265,7 +265,7 @@ static int dummy_inode_init_security (st
 }
 
 static int dummy_inode_create (struct inode *inode, struct dentry *dentry,
-			       int mask)
+			       struct vfsmount *mnt, int mask)
 {
 	return 0;
 }
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2178,7 +2178,8 @@ static int selinux_inode_init_security(s
 	return 0;
 }
 
-static int selinux_inode_create(struct inode *dir, struct dentry *dentry, int mask)
+static int selinux_inode_create(struct inode *dir, struct dentry *dentry,
+				 struct vfsmount *mnt, int mask)
 {
 	return may_create(dir, dentry, SECCLASS_FILE);
 }

-- 

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

* [AppArmor 02/41] Remove redundant check from proc_setattr()
  2007-04-12  9:08 [AppArmor 00/41] AppArmor security module overview jjohansen
  2007-04-12  9:08 ` [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook jjohansen
@ 2007-04-12  9:08 ` jjohansen
  2007-04-12  9:08 ` [AppArmor 03/41] Remove redundant check from proc_sys_setattr() jjohansen
                   ` (41 subsequent siblings)
  43 siblings, 0 replies; 187+ messages in thread
From: jjohansen @ 2007-04-12  9:08 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, linux-fsdevel, chrisw, Tony Jones,
	Andreas Gruenbacher, John Johansen

[-- Attachment #1: proc_setattr.diff --]
[-- Type: text/plain, Size: 681 bytes --]

notify_change() already calls security_inode_setattr() before
calling iop->setattr.

Signed-off-by: Tony Jones <tonyj@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>

---
 fs/proc/base.c |    7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -344,11 +344,8 @@ static int proc_setattr(struct dentry *d
 		return -EPERM;
 
 	error = inode_change_ok(inode, attr);
-	if (!error) {
-		error = security_inode_setattr(dentry, attr);
-		if (!error)
-			error = inode_setattr(inode, attr);
-	}
+	if (!error)
+		error = inode_setattr(inode, attr);
 	return error;
 }
 

-- 

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

* [AppArmor 03/41] Remove redundant check from proc_sys_setattr()
  2007-04-12  9:08 [AppArmor 00/41] AppArmor security module overview jjohansen
  2007-04-12  9:08 ` [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook jjohansen
  2007-04-12  9:08 ` [AppArmor 02/41] Remove redundant check from proc_setattr() jjohansen
@ 2007-04-12  9:08 ` jjohansen
  2007-04-12 10:10   ` Alan Cox
  2007-04-12  9:08 ` [AppArmor 04/41] Pass struct file down to remove_suid and children jjohansen
                   ` (40 subsequent siblings)
  43 siblings, 1 reply; 187+ messages in thread
From: jjohansen @ 2007-04-12  9:08 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, linux-fsdevel, chrisw, Steve Beattie,
	Andreas Gruenbacher, John Johansen

[-- Attachment #1: proc_sys_setattr.diff --]
[-- Type: text/plain, Size: 708 bytes --]

notify_change() already calls security_inode_setattr() before
calling iop->setattr.

Signed-off-by: Steve Beattie <sbeattie@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>

---
 fs/proc/proc_sysctl.c |    7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

--- a/fs/proc/proc_sysctl.c
+++ b/fs/proc/proc_sysctl.c
@@ -429,11 +429,8 @@ static int proc_sys_setattr(struct dentr
 		return -EPERM;
 
 	error = inode_change_ok(inode, attr);
-	if (!error) {
-		error = security_inode_setattr(dentry, attr);
-		if (!error)
-			error = inode_setattr(inode, attr);
-	}
+	if (!error)
+		error = inode_setattr(inode, attr);
 
 	return error;
 }

-- 

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

* [AppArmor 04/41] Pass struct file down to remove_suid and children
  2007-04-12  9:08 [AppArmor 00/41] AppArmor security module overview jjohansen
                   ` (2 preceding siblings ...)
  2007-04-12  9:08 ` [AppArmor 03/41] Remove redundant check from proc_sys_setattr() jjohansen
@ 2007-04-12  9:08 ` jjohansen
  2007-04-12  9:08 ` [AppArmor 05/41] Add a vfsmount parameter to notify_change() jjohansen
                   ` (39 subsequent siblings)
  43 siblings, 0 replies; 187+ messages in thread
From: jjohansen @ 2007-04-12  9:08 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, linux-fsdevel, chrisw, Tony Jones,
	Andreas Gruenbacher, John Johansen

[-- Attachment #1: remove_suid.diff --]
[-- Type: text/plain, Size: 6036 bytes --]

Pass struct path to remove_suid and should_remove_suid instead of
only the dentry. Required by a later patch that adds a struct
vfsmount parameter to notify_change().

Signed-off-by: Tony Jones <tonyj@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>

---
 fs/ntfs/file.c             |    2 +-
 fs/ocfs2/file.c            |   10 +++++-----
 fs/reiserfs/file.c         |    2 +-
 fs/splice.c                |    6 +++---
 fs/xfs/linux-2.6/xfs_lrw.c |    2 +-
 include/linux/fs.h         |    6 +++---
 mm/filemap.c               |   16 ++++++++--------
 mm/filemap_xip.c           |    2 +-
 mm/shmem.c                 |    2 +-
 9 files changed, 24 insertions(+), 24 deletions(-)

--- a/fs/ntfs/file.c
+++ b/fs/ntfs/file.c
@@ -2162,7 +2162,7 @@ static ssize_t ntfs_file_aio_write_noloc
 		goto out;
 	if (!count)
 		goto out;
-	err = remove_suid(file->f_path.dentry);
+	err = remove_suid(&file->f_path);
 	if (err)
 		goto out;
 	file_update_time(file);
--- a/fs/ocfs2/file.c
+++ b/fs/ocfs2/file.c
@@ -1035,13 +1035,13 @@ out:
 	return ret;
 }
 
-static int ocfs2_prepare_inode_for_write(struct dentry *dentry,
+static int ocfs2_prepare_inode_for_write(struct path *path,
 					 loff_t *ppos,
 					 size_t count,
 					 int appending)
 {
 	int ret = 0, meta_level = appending;
-	struct inode *inode = dentry->d_inode;
+	struct inode *inode = path->dentry->d_inode;
 	u32 clusters;
 	loff_t newsize, saved_pos;
 
@@ -1067,7 +1067,7 @@ static int ocfs2_prepare_inode_for_write
 		 * inode. There's also the dinode i_size state which
 		 * can be lost via setattr during extending writes (we
 		 * set inode->i_size at the end of a write. */
-		if (should_remove_suid(dentry)) {
+		if (should_remove_suid(path)) {
 			if (meta_level == 0) {
 				ocfs2_meta_unlock(inode, meta_level);
 				meta_level = 1;
@@ -1176,7 +1176,7 @@ static ssize_t ocfs2_file_aio_write(stru
 		goto out;
 	}
 
-	ret = ocfs2_prepare_inode_for_write(filp->f_path.dentry, &iocb->ki_pos,
+	ret = ocfs2_prepare_inode_for_write(&filp->f_path, &iocb->ki_pos,
 					    iocb->ki_left, appending);
 	if (ret < 0) {
 		mlog_errno(ret);
@@ -1239,7 +1239,7 @@ static ssize_t ocfs2_file_splice_write(s
 		goto out;
 	}
 
-	ret = ocfs2_prepare_inode_for_write(out->f_path.dentry, ppos, len, 0);
+	ret = ocfs2_prepare_inode_for_write(&out->f_path, ppos, len, 0);
 	if (ret < 0) {
 		mlog_errno(ret);
 		goto out_unlock;
--- a/fs/reiserfs/file.c
+++ b/fs/reiserfs/file.c
@@ -1353,7 +1353,7 @@ static ssize_t reiserfs_file_write(struc
 	if (count == 0)
 		goto out;
 
-	res = remove_suid(file->f_path.dentry);
+	res = remove_suid(&file->f_path);
 	if (res)
 		goto out;
 
--- a/fs/splice.c
+++ b/fs/splice.c
@@ -797,7 +797,7 @@ generic_file_splice_write_nolock(struct 
 	ssize_t ret;
 	int err;
 
-	err = remove_suid(out->f_path.dentry);
+	err = remove_suid(&out->f_path);
 	if (unlikely(err))
 		return err;
 
@@ -843,10 +843,10 @@ generic_file_splice_write(struct pipe_in
 	ssize_t ret;
 	int err;
 
-	err = should_remove_suid(out->f_path.dentry);
+	err = should_remove_suid(&out->f_path);
 	if (unlikely(err)) {
 		mutex_lock(&inode->i_mutex);
-		err = __remove_suid(out->f_path.dentry, err);
+		err = __remove_suid(&out->f_path, err);
 		mutex_unlock(&inode->i_mutex);
 		if (err)
 			return err;
--- a/fs/xfs/linux-2.6/xfs_lrw.c
+++ b/fs/xfs/linux-2.6/xfs_lrw.c
@@ -799,7 +799,7 @@ start:
 	     !capable(CAP_FSETID)) {
 		error = xfs_write_clear_setuid(xip);
 		if (likely(!error))
-			error = -remove_suid(file->f_path.dentry);
+			error = -remove_suid(&file->f_path);
 		if (unlikely(error)) {
 			xfs_iunlock(xip, iolock);
 			goto out_unlock_mutex;
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1685,9 +1685,9 @@ extern void __iget(struct inode * inode)
 extern void clear_inode(struct inode *);
 extern void destroy_inode(struct inode *);
 extern struct inode *new_inode(struct super_block *);
-extern int __remove_suid(struct dentry *, int);
-extern int should_remove_suid(struct dentry *);
-extern int remove_suid(struct dentry *);
+extern int __remove_suid(struct path *, int);
+extern int should_remove_suid(struct path *);
+extern int remove_suid(struct path *);
 
 extern void __insert_inode_hash(struct inode *, unsigned long hashval);
 extern void remove_inode_hash(struct inode *);
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -1849,9 +1849,9 @@ repeat:
  *	if suid or (sgid and xgrp)
  *		remove privs
  */
-int should_remove_suid(struct dentry *dentry)
+int should_remove_suid(struct path *path)
 {
-	mode_t mode = dentry->d_inode->i_mode;
+	mode_t mode = path->dentry->d_inode->i_mode;
 	int kill = 0;
 
 	/* suid always must be killed */
@@ -1872,20 +1872,20 @@ int should_remove_suid(struct dentry *de
 }
 EXPORT_SYMBOL(should_remove_suid);
 
-int __remove_suid(struct dentry *dentry, int kill)
+int __remove_suid(struct path *path, int kill)
 {
 	struct iattr newattrs;
 
 	newattrs.ia_valid = ATTR_FORCE | kill;
-	return notify_change(dentry, &newattrs);
+	return notify_change(path->dentry, &newattrs);
 }
 
-int remove_suid(struct dentry *dentry)
+int remove_suid(struct path *path)
 {
-	int kill = should_remove_suid(dentry);
+	int kill = should_remove_suid(path);
 
 	if (unlikely(kill))
-		return __remove_suid(dentry, kill);
+		return __remove_suid(path, kill);
 
 	return 0;
 }
@@ -2252,7 +2252,7 @@ __generic_file_aio_write_nolock(struct k
 	if (count == 0)
 		goto out;
 
-	err = remove_suid(file->f_path.dentry);
+	err = remove_suid(&file->f_path);
 	if (err)
 		goto out;
 
--- a/mm/filemap_xip.c
+++ b/mm/filemap_xip.c
@@ -405,7 +405,7 @@ xip_file_write(struct file *filp, const 
 	if (count == 0)
 		goto out_backing;
 
-	ret = remove_suid(filp->f_path.dentry);
+	ret = remove_suid(&filp->f_path);
 	if (ret)
 		goto out_backing;
 
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -1516,7 +1516,7 @@ shmem_file_write(struct file *file, cons
 	if (err || !count)
 		goto out;
 
-	err = remove_suid(file->f_path.dentry);
+	err = remove_suid(&file->f_path);
 	if (err)
 		goto out;
 

-- 

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

* [AppArmor 05/41] Add a vfsmount parameter to notify_change()
  2007-04-12  9:08 [AppArmor 00/41] AppArmor security module overview jjohansen
                   ` (3 preceding siblings ...)
  2007-04-12  9:08 ` [AppArmor 04/41] Pass struct file down to remove_suid and children jjohansen
@ 2007-04-12  9:08 ` jjohansen
  2007-04-12  9:08 ` [AppArmor 06/41] Pass struct vfsmount to the inode_setattr LSM hook jjohansen
                   ` (38 subsequent siblings)
  43 siblings, 0 replies; 187+ messages in thread
From: jjohansen @ 2007-04-12  9:08 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, linux-fsdevel, chrisw, Tony Jones,
	Andreas Gruenbacher, John Johansen

[-- Attachment #1: vfs-notify_change.diff --]
[-- Type: text/plain, Size: 11606 bytes --]

The vfsmount parameter must be set appropriately for files visibile
outside the kernel. Files that are only used in a filesystem (e.g.,
reiserfs xattr files) will have a NULL vfsmount.

Signed-off-by: Tony Jones <tonyj@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>

---
 fs/attr.c           |    3 ++-
 fs/ecryptfs/inode.c |    4 +++-
 fs/exec.c           |    3 ++-
 fs/fat/file.c       |    2 +-
 fs/hpfs/namei.c     |    2 +-
 fs/namei.c          |    3 ++-
 fs/nfsd/vfs.c       |    8 ++++----
 fs/open.c           |   28 +++++++++++++++-------------
 fs/reiserfs/xattr.c |    6 +++---
 fs/sysfs/file.c     |    2 +-
 fs/utimes.c         |    4 ++--
 include/linux/fs.h  |    6 +++---
 mm/filemap.c        |    2 +-
 mm/tiny-shmem.c     |    2 +-
 14 files changed, 41 insertions(+), 34 deletions(-)

--- a/fs/attr.c
+++ b/fs/attr.c
@@ -101,7 +101,8 @@ int inode_setattr(struct inode * inode, 
 }
 EXPORT_SYMBOL(inode_setattr);
 
-int notify_change(struct dentry * dentry, struct iattr * attr)
+int notify_change(struct dentry *dentry, struct vfsmount *mnt,
+		  struct iattr *attr)
 {
 	struct inode *inode = dentry->d_inode;
 	mode_t mode;
--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c
@@ -870,12 +870,14 @@ static int ecryptfs_setattr(struct dentr
 {
 	int rc = 0;
 	struct dentry *lower_dentry;
+	struct vfsmount *lower_mnt;
 	struct inode *inode;
 	struct inode *lower_inode;
 	struct ecryptfs_crypt_stat *crypt_stat;
 
 	crypt_stat = &ecryptfs_inode_to_private(dentry->d_inode)->crypt_stat;
 	lower_dentry = ecryptfs_dentry_to_lower(dentry);
+	lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry);
 	inode = dentry->d_inode;
 	lower_inode = ecryptfs_inode_to_lower(inode);
 	if (ia->ia_valid & ATTR_SIZE) {
@@ -890,7 +892,7 @@ static int ecryptfs_setattr(struct dentr
 		if (rc < 0)
 			goto out;
 	}
-	rc = notify_change(lower_dentry, ia);
+	rc = notify_change(lower_dentry, lower_mnt, ia);
 out:
 	fsstack_copy_attr_all(inode, lower_inode, NULL);
 	return rc;
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1532,7 +1532,8 @@ int do_coredump(long signr, int exit_cod
 		goto close_fail;
 	if (!file->f_op->write)
 		goto close_fail;
-	if (!ispipe && do_truncate(file->f_path.dentry, 0, 0, file) != 0)
+	if (!ispipe &&
+	    do_truncate(file->f_path.dentry, file->f_path.mnt, 0, 0, file) != 0)
 		goto close_fail;
 
 	retval = binfmt->core_dump(signr, regs, file);
--- a/fs/fat/file.c
+++ b/fs/fat/file.c
@@ -92,7 +92,7 @@ int fat_generic_ioctl(struct inode *inod
 		}
 
 		/* This MUST be done before doing anything irreversible... */
-		err = notify_change(filp->f_path.dentry, &ia);
+		err = notify_change(filp->f_path.dentry, filp->f_path.mnt, &ia);
 		if (err)
 			goto up;
 
--- a/fs/hpfs/namei.c
+++ b/fs/hpfs/namei.c
@@ -426,7 +426,7 @@ again:
 			/*printk("HPFS: truncating file before delete.\n");*/
 			newattrs.ia_size = 0;
 			newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
-			err = notify_change(dentry, &newattrs);
+			err = notify_change(dentry, NULL, &newattrs);
 			put_write_access(inode);
 			if (!err)
 				goto again;
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1580,7 +1580,8 @@ int may_open(struct nameidata *nd, int a
 		if (!error) {
 			DQUOT_INIT(inode);
 			
-			error = do_truncate(dentry, 0, ATTR_MTIME|ATTR_CTIME, NULL);
+			error = do_truncate(dentry, nd->mnt, 0,
+					    ATTR_MTIME|ATTR_CTIME, NULL);
 		}
 		put_write_access(inode);
 		if (error)
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -358,7 +358,7 @@ nfsd_setattr(struct svc_rqst *rqstp, str
 	err = nfserr_notsync;
 	if (!check_guard || guardtime == inode->i_ctime.tv_sec) {
 		fh_lock(fhp);
-		host_err = notify_change(dentry, iap);
+		host_err = notify_change(dentry, fhp->fh_export->ex_mnt, iap);
 		err = nfserrno(host_err);
 		fh_unlock(fhp);
 	}
@@ -893,13 +893,13 @@ out:
 	return err;
 }
 
-static void kill_suid(struct dentry *dentry)
+static void kill_suid(struct dentry *dentry, struct vfsmount *mnt)
 {
 	struct iattr	ia;
 	ia.ia_valid = ATTR_KILL_SUID | ATTR_KILL_SGID;
 
 	mutex_lock(&dentry->d_inode->i_mutex);
-	notify_change(dentry, &ia);
+	notify_change(dentry, mnt, &ia);
 	mutex_unlock(&dentry->d_inode->i_mutex);
 }
 
@@ -958,7 +958,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, s
 
 	/* clear setuid/setgid flag after write */
 	if (host_err >= 0 && (inode->i_mode & (S_ISUID | S_ISGID)))
-		kill_suid(dentry);
+		kill_suid(dentry, exp->ex_mnt);
 
 	if (host_err >= 0 && stable) {
 		static ino_t	last_ino;
--- a/fs/open.c
+++ b/fs/open.c
@@ -194,8 +194,8 @@ out:
 	return error;
 }
 
-int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs,
-	struct file *filp)
+int do_truncate(struct dentry *dentry, struct vfsmount *mnt, loff_t length,
+		unsigned int time_attrs, struct file *filp)
 {
 	int err;
 	struct iattr newattrs;
@@ -212,7 +212,7 @@ int do_truncate(struct dentry *dentry, l
 	}
 
 	mutex_lock(&dentry->d_inode->i_mutex);
-	err = notify_change(dentry, &newattrs);
+	err = notify_change(dentry, mnt, &newattrs);
 	mutex_unlock(&dentry->d_inode->i_mutex);
 	return err;
 }
@@ -267,7 +267,7 @@ static long do_sys_truncate(const char _
 	error = locks_verify_truncate(inode, NULL, length);
 	if (!error) {
 		DQUOT_INIT(inode);
-		error = do_truncate(nd.dentry, length, 0, NULL);
+		error = do_truncate(nd.dentry, nd.mnt, length, 0, NULL);
 	}
 	put_write_access(inode);
 
@@ -319,7 +319,8 @@ static long do_sys_ftruncate(unsigned in
 
 	error = locks_verify_truncate(inode, file, length);
 	if (!error)
-		error = do_truncate(dentry, length, ATTR_MTIME|ATTR_CTIME, file);
+		error = do_truncate(dentry, file->f_path.mnt, length,
+				    ATTR_MTIME|ATTR_CTIME, file);
 out_putf:
 	fput(file);
 out:
@@ -519,7 +520,7 @@ asmlinkage long sys_fchmod(unsigned int 
 		mode = inode->i_mode;
 	newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
 	newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
-	err = notify_change(dentry, &newattrs);
+	err = notify_change(dentry, file->f_path.mnt, &newattrs);
 	mutex_unlock(&inode->i_mutex);
 
 out_putf:
@@ -554,7 +555,7 @@ asmlinkage long sys_fchmodat(int dfd, co
 		mode = inode->i_mode;
 	newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
 	newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
-	error = notify_change(nd.dentry, &newattrs);
+	error = notify_change(nd.dentry, nd.mnt, &newattrs);
 	mutex_unlock(&inode->i_mutex);
 
 dput_and_out:
@@ -568,7 +569,8 @@ asmlinkage long sys_chmod(const char __u
 	return sys_fchmodat(AT_FDCWD, filename, mode);
 }
 
-static int chown_common(struct dentry * dentry, uid_t user, gid_t group)
+static int chown_common(struct dentry * dentry, struct vfsmount *mnt,
+			uid_t user, gid_t group)
 {
 	struct inode * inode;
 	int error;
@@ -597,7 +599,7 @@ static int chown_common(struct dentry * 
 	if (!S_ISDIR(inode->i_mode))
 		newattrs.ia_valid |= ATTR_KILL_SUID|ATTR_KILL_SGID;
 	mutex_lock(&inode->i_mutex);
-	error = notify_change(dentry, &newattrs);
+	error = notify_change(dentry, mnt, &newattrs);
 	mutex_unlock(&inode->i_mutex);
 out:
 	return error;
@@ -611,7 +613,7 @@ asmlinkage long sys_chown(const char __u
 	error = user_path_walk(filename, &nd);
 	if (error)
 		goto out;
-	error = chown_common(nd.dentry, user, group);
+	error = chown_common(nd.dentry, nd.mnt, user, group);
 	path_release(&nd);
 out:
 	return error;
@@ -631,7 +633,7 @@ asmlinkage long sys_fchownat(int dfd, co
 	error = __user_walk_fd(dfd, filename, follow, &nd);
 	if (error)
 		goto out;
-	error = chown_common(nd.dentry, user, group);
+	error = chown_common(nd.dentry, nd.mnt, user, group);
 	path_release(&nd);
 out:
 	return error;
@@ -645,7 +647,7 @@ asmlinkage long sys_lchown(const char __
 	error = user_path_walk_link(filename, &nd);
 	if (error)
 		goto out;
-	error = chown_common(nd.dentry, user, group);
+	error = chown_common(nd.dentry, nd.mnt, user, group);
 	path_release(&nd);
 out:
 	return error;
@@ -664,7 +666,7 @@ asmlinkage long sys_fchown(unsigned int 
 
 	dentry = file->f_path.dentry;
 	audit_inode(NULL, dentry->d_inode);
-	error = chown_common(dentry, user, group);
+	error = chown_common(dentry, file->f_path.mnt, user, group);
 	fput(file);
 out:
 	return error;
--- a/fs/reiserfs/xattr.c
+++ b/fs/reiserfs/xattr.c
@@ -527,7 +527,7 @@ reiserfs_xattr_set(struct inode *inode, 
 	newattrs.ia_size = buffer_size;
 	newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
 	mutex_lock(&xinode->i_mutex);
-	err = notify_change(fp->f_path.dentry, &newattrs);
+	err = notify_change(fp->f_path.dentry, NULL, &newattrs);
 	if (err)
 		goto out_filp;
 
@@ -867,7 +867,7 @@ reiserfs_chown_xattrs_filler(void *buf, 
 	}
 
 	if (!S_ISDIR(xafile->d_inode->i_mode))
-		err = notify_change(xafile, attrs);
+		err = notify_change(xafile, NULL, attrs);
 	dput(xafile);
 
 	return err;
@@ -919,7 +919,7 @@ int reiserfs_chown_xattrs(struct inode *
 		goto out_dir;
 	}
 
-	err = notify_change(dir, attrs);
+	err = notify_change(dir, NULL, attrs);
 	unlock_kernel();
 
       out_dir:
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -584,7 +584,7 @@ int sysfs_chmod_file(struct kobject *kob
 			newattrs.ia_mode = (mode & S_IALLUGO) |
 						(inode->i_mode & ~S_IALLUGO);
 			newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
-			res = notify_change(victim, &newattrs);
+			res = notify_change(victim, NULL, &newattrs);
 			mutex_unlock(&inode->i_mutex);
 		}
 		dput(victim);
--- a/fs/utimes.c
+++ b/fs/utimes.c
@@ -62,7 +62,7 @@ asmlinkage long sys_utime(char __user * 
 			goto dput_and_out;
 	}
 	mutex_lock(&inode->i_mutex);
-	error = notify_change(nd.dentry, &newattrs);
+	error = notify_change(nd.dentry, nd.mnt, &newattrs);
 	mutex_unlock(&inode->i_mutex);
 dput_and_out:
 	path_release(&nd);
@@ -115,7 +115,7 @@ long do_utimes(int dfd, char __user *fil
 			goto dput_and_out;
 	}
 	mutex_lock(&inode->i_mutex);
-	error = notify_change(nd.dentry, &newattrs);
+	error = notify_change(nd.dentry, nd.mnt, &newattrs);
 	mutex_unlock(&inode->i_mutex);
 dput_and_out:
 	path_release(&nd);
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1458,8 +1458,8 @@ static inline int break_lease(struct ino
 
 /* fs/open.c */
 
-extern int do_truncate(struct dentry *, loff_t start, unsigned int time_attrs,
-		       struct file *filp);
+extern int do_truncate(struct dentry *, struct vfsmount *, loff_t start,
+		       unsigned int time_attrs, struct file *filp);
 extern long do_sys_open(int fdf, const char __user *filename, int flags,
 			int mode);
 extern struct file *filp_open(const char *, int, int);
@@ -1612,7 +1612,7 @@ extern int do_remount_sb(struct super_bl
 #ifdef CONFIG_BLOCK
 extern sector_t bmap(struct inode *, sector_t);
 #endif
-extern int notify_change(struct dentry *, struct iattr *);
+extern int notify_change(struct dentry *, struct vfsmount *, struct iattr *);
 extern int permission(struct inode *, int, struct nameidata *);
 extern int generic_permission(struct inode *, int,
 		int (*check_acl)(struct inode *, int));
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -1877,7 +1877,7 @@ int __remove_suid(struct path *path, int
 	struct iattr newattrs;
 
 	newattrs.ia_valid = ATTR_FORCE | kill;
-	return notify_change(path->dentry, &newattrs);
+	return notify_change(path->dentry, path->mnt, &newattrs);
 }
 
 int remove_suid(struct path *path)
--- a/mm/tiny-shmem.c
+++ b/mm/tiny-shmem.c
@@ -86,7 +86,7 @@ struct file *shmem_file_setup(char *name
 	file->f_mode = FMODE_WRITE | FMODE_READ;
 
 	/* notify everyone as to the change of file size */
-	error = do_truncate(dentry, size, 0, file);
+	error = do_truncate(dentry, file->f_path.mnt, size, 0, file);
 	if (error < 0)
 		goto close_file;
 

-- 

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

* [AppArmor 06/41] Pass struct vfsmount to the inode_setattr LSM hook
  2007-04-12  9:08 [AppArmor 00/41] AppArmor security module overview jjohansen
                   ` (4 preceding siblings ...)
  2007-04-12  9:08 ` [AppArmor 05/41] Add a vfsmount parameter to notify_change() jjohansen
@ 2007-04-12  9:08 ` jjohansen
  2007-04-12  9:08 ` [AppArmor 07/41] Add struct vfsmount parameter to vfs_mkdir() jjohansen
                   ` (37 subsequent siblings)
  43 siblings, 0 replies; 187+ messages in thread
From: jjohansen @ 2007-04-12  9:08 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, linux-fsdevel, chrisw, Tony Jones,
	Andreas Gruenbacher, John Johansen

[-- Attachment #1: security-setattr.diff --]
[-- Type: text/plain, Size: 3676 bytes --]

This is needed for computing pathnames in the AppArmor LSM.

Signed-off-by: Tony Jones <tonyj@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>

---
 fs/attr.c                |    4 ++--
 include/linux/security.h |    8 ++++++--
 security/dummy.c         |    3 ++-
 security/selinux/hooks.c |    5 +++--
 4 files changed, 13 insertions(+), 7 deletions(-)

--- a/fs/attr.c
+++ b/fs/attr.c
@@ -145,13 +145,13 @@ int notify_change(struct dentry *dentry,
 		down_write(&dentry->d_inode->i_alloc_sem);
 
 	if (inode->i_op && inode->i_op->setattr) {
-		error = security_inode_setattr(dentry, attr);
+		error = security_inode_setattr(dentry, mnt, attr);
 		if (!error)
 			error = inode->i_op->setattr(dentry, attr);
 	} else {
 		error = inode_change_ok(inode, attr);
 		if (!error)
-			error = security_inode_setattr(dentry, attr);
+			error = security_inode_setattr(dentry, mnt, attr);
 		if (!error) {
 			if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) ||
 			    (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid))
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -358,6 +358,7 @@ struct request_sock;
  *	file attributes change (such as when a file is truncated, chown/chmod
  *	operations, transferring disk quotas, etc).
  *	@dentry contains the dentry structure for the file.
+ *	@mnt is the vfsmount corresponding to @dentry (may be NULL).
  *	@attr is the iattr structure containing the new file attributes.
  *	Return 0 if permission is granted.
  * @inode_getattr:
@@ -1221,7 +1222,8 @@ struct security_operations {
 	int (*inode_readlink) (struct dentry *dentry);
 	int (*inode_follow_link) (struct dentry *dentry, struct nameidata *nd);
 	int (*inode_permission) (struct inode *inode, int mask, struct nameidata *nd);
-	int (*inode_setattr)	(struct dentry *dentry, struct iattr *attr);
+	int (*inode_setattr) (struct dentry *dentry, struct vfsmount *mnt,
+			      struct iattr *attr);
 	int (*inode_getattr) (struct vfsmount *mnt, struct dentry *dentry);
         void (*inode_delete) (struct inode *inode);
 	int (*inode_setxattr) (struct dentry *dentry, char *name, void *value,
@@ -1708,11 +1710,12 @@ static inline int security_inode_permiss
 }
 
 static inline int security_inode_setattr (struct dentry *dentry,
+					  struct vfsmount *mnt,
 					  struct iattr *attr)
 {
 	if (unlikely (IS_PRIVATE (dentry->d_inode)))
 		return 0;
-	return security_ops->inode_setattr (dentry, attr);
+	return security_ops->inode_setattr (dentry, mnt, attr);
 }
 
 static inline int security_inode_getattr (struct vfsmount *mnt,
@@ -2412,6 +2415,7 @@ static inline int security_inode_permiss
 }
 
 static inline int security_inode_setattr (struct dentry *dentry,
+					  struct vfsmount *mnt,
 					  struct iattr *attr)
 {
 	return 0;
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -328,7 +328,8 @@ static int dummy_inode_permission (struc
 	return 0;
 }
 
-static int dummy_inode_setattr (struct dentry *dentry, struct iattr *iattr)
+static int dummy_inode_setattr (struct dentry *dentry, struct vfsmount *mnt,
+				struct iattr *iattr)
 {
 	return 0;
 }
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2269,11 +2269,12 @@ static int selinux_inode_permission(stru
 			       file_mask_to_av(inode->i_mode, mask), NULL);
 }
 
-static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
+static int selinux_inode_setattr(struct dentry *dentry, struct vfsmount *mnt,
+				 struct iattr *iattr)
 {
 	int rc;
 
-	rc = secondary_ops->inode_setattr(dentry, iattr);
+	rc = secondary_ops->inode_setattr(dentry, mnt, iattr);
 	if (rc)
 		return rc;
 

-- 

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

* [AppArmor 07/41] Add struct vfsmount parameter to vfs_mkdir()
  2007-04-12  9:08 [AppArmor 00/41] AppArmor security module overview jjohansen
                   ` (5 preceding siblings ...)
  2007-04-12  9:08 ` [AppArmor 06/41] Pass struct vfsmount to the inode_setattr LSM hook jjohansen
@ 2007-04-12  9:08 ` jjohansen
  2007-04-12  9:08 ` [AppArmor 08/41] Pass struct vfsmount to the inode_mkdir LSM hook jjohansen
                   ` (36 subsequent siblings)
  43 siblings, 0 replies; 187+ messages in thread
From: jjohansen @ 2007-04-12  9:08 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, linux-fsdevel, chrisw, Tony Jones,
	Andreas Gruenbacher, John Johansen

[-- Attachment #1: vfs-mkdir.diff --]
[-- Type: text/plain, Size: 3171 bytes --]

The vfsmount will be passed down to the LSM hook so that LSMs can compute
pathnames.

Signed-off-by: Tony Jones <tonyj@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>

---
 fs/ecryptfs/inode.c   |    5 ++++-
 fs/namei.c            |    5 +++--
 fs/nfsd/nfs4recover.c |    3 ++-
 fs/nfsd/vfs.c         |    3 ++-
 include/linux/fs.h    |    2 +-
 5 files changed, 12 insertions(+), 6 deletions(-)

--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c
@@ -509,11 +509,14 @@ static int ecryptfs_mkdir(struct inode *
 {
 	int rc;
 	struct dentry *lower_dentry;
+	struct vfsmount *lower_mnt;
 	struct dentry *lower_dir_dentry;
 
 	lower_dentry = ecryptfs_dentry_to_lower(dentry);
+	lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry);
 	lower_dir_dentry = lock_parent(lower_dentry);
-	rc = vfs_mkdir(lower_dir_dentry->d_inode, lower_dentry, mode);
+	rc = vfs_mkdir(lower_dir_dentry->d_inode, lower_dentry, lower_mnt,
+		       mode);
 	if (rc || !lower_dentry->d_inode)
 		goto out;
 	rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb, 0);
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1916,7 +1916,8 @@ asmlinkage long sys_mknod(const char __u
 	return sys_mknodat(AT_FDCWD, filename, mode, dev);
 }
 
-int vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
+int vfs_mkdir(struct inode *dir, struct dentry *dentry, struct vfsmount *mnt,
+	      int mode)
 {
 	int error = may_create(dir, dentry, NULL);
 
@@ -1960,7 +1961,7 @@ asmlinkage long sys_mkdirat(int dfd, con
 
 	if (!IS_POSIXACL(nd.dentry->d_inode))
 		mode &= ~current->fs->umask;
-	error = vfs_mkdir(nd.dentry->d_inode, dentry, mode);
+	error = vfs_mkdir(nd.dentry->d_inode, dentry, nd.mnt, mode);
 	dput(dentry);
 out_unlock:
 	mutex_unlock(&nd.dentry->d_inode->i_mutex);
--- a/fs/nfsd/nfs4recover.c
+++ b/fs/nfsd/nfs4recover.c
@@ -156,7 +156,8 @@ nfsd4_create_clid_dir(struct nfs4_client
 		dprintk("NFSD: nfsd4_create_clid_dir: DIRECTORY EXISTS\n");
 		goto out_put;
 	}
-	status = vfs_mkdir(rec_dir.dentry->d_inode, dentry, S_IRWXU);
+	status = vfs_mkdir(rec_dir.dentry->d_inode, dentry, rec_dir.mnt,
+			   S_IRWXU);
 out_put:
 	dput(dentry);
 out_unlock:
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -1186,7 +1186,8 @@ nfsd_create(struct svc_rqst *rqstp, stru
 		host_err = vfs_create(dirp, dchild, iap->ia_mode, NULL);
 		break;
 	case S_IFDIR:
-		host_err = vfs_mkdir(dirp, dchild, iap->ia_mode);
+		host_err = vfs_mkdir(dirp, dchild, fhp->fh_export->ex_mnt,
+				     iap->ia_mode);
 		break;
 	case S_IFCHR:
 	case S_IFBLK:
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -980,7 +980,7 @@ extern void unlock_super(struct super_bl
  */
 extern int vfs_permission(struct nameidata *, int);
 extern int vfs_create(struct inode *, struct dentry *, int, struct nameidata *);
-extern int vfs_mkdir(struct inode *, struct dentry *, int);
+extern int vfs_mkdir(struct inode *, struct dentry *, struct vfsmount *, int);
 extern int vfs_mknod(struct inode *, struct dentry *, int, dev_t);
 extern int vfs_symlink(struct inode *, struct dentry *, const char *, int);
 extern int vfs_link(struct dentry *, struct inode *, struct dentry *);

-- 

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

* [AppArmor 08/41] Pass struct vfsmount to the inode_mkdir LSM hook
  2007-04-12  9:08 [AppArmor 00/41] AppArmor security module overview jjohansen
                   ` (6 preceding siblings ...)
  2007-04-12  9:08 ` [AppArmor 07/41] Add struct vfsmount parameter to vfs_mkdir() jjohansen
@ 2007-04-12  9:08 ` jjohansen
  2007-04-12  9:08 ` [AppArmor 09/41] Add a struct vfsmount parameter to vfs_mknod() jjohansen
                   ` (35 subsequent siblings)
  43 siblings, 0 replies; 187+ messages in thread
From: jjohansen @ 2007-04-12  9:08 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, linux-fsdevel, chrisw, Tony Jones,
	Andreas Gruenbacher, John Johansen

[-- Attachment #1: security-mkdir.diff --]
[-- Type: text/plain, Size: 3092 bytes --]

This is needed for computing pathnames in the AppArmor LSM.

Signed-off-by: Tony Jones <tonyj@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>

---
 fs/namei.c               |    2 +-
 include/linux/security.h |    8 ++++++--
 security/dummy.c         |    2 +-
 security/selinux/hooks.c |    3 ++-
 4 files changed, 10 insertions(+), 5 deletions(-)

--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1928,7 +1928,7 @@ int vfs_mkdir(struct inode *dir, struct 
 		return -EPERM;
 
 	mode &= (S_IRWXUGO|S_ISVTX);
-	error = security_inode_mkdir(dir, dentry, mode);
+	error = security_inode_mkdir(dir, dentry, mnt, mode);
 	if (error)
 		return error;
 
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -308,6 +308,7 @@ struct request_sock;
  *	associated with inode strcture @dir. 
  *	@dir containst the inode structure of parent of the directory to be created.
  *	@dentry contains the dentry structure of new directory.
+ *	@mnt is the vfsmount corresponding to @dentry (may be NULL).
  *	@mode contains the mode of new directory.
  *	Return 0 if permission is granted.
  * @inode_rmdir:
@@ -1213,7 +1214,8 @@ struct security_operations {
 	int (*inode_unlink) (struct inode *dir, struct dentry *dentry);
 	int (*inode_symlink) (struct inode *dir,
 	                      struct dentry *dentry, const char *old_name);
-	int (*inode_mkdir) (struct inode *dir, struct dentry *dentry, int mode);
+	int (*inode_mkdir) (struct inode *dir, struct dentry *dentry,
+			    struct vfsmount *mnt, int mode);
 	int (*inode_rmdir) (struct inode *dir, struct dentry *dentry);
 	int (*inode_mknod) (struct inode *dir, struct dentry *dentry,
 	                    int mode, dev_t dev);
@@ -1650,11 +1652,12 @@ static inline int security_inode_symlink
 
 static inline int security_inode_mkdir (struct inode *dir,
 					struct dentry *dentry,
+					struct vfsmount *mnt,
 					int mode)
 {
 	if (unlikely (IS_PRIVATE (dir)))
 		return 0;
-	return security_ops->inode_mkdir (dir, dentry, mode);
+	return security_ops->inode_mkdir (dir, dentry, mnt, mode);
 }
 
 static inline int security_inode_rmdir (struct inode *dir,
@@ -2371,6 +2374,7 @@ static inline int security_inode_symlink
 
 static inline int security_inode_mkdir (struct inode *dir,
 					struct dentry *dentry,
+					struct vfsmount *mnt,
 					int mode)
 {
 	return 0;
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -288,7 +288,7 @@ static int dummy_inode_symlink (struct i
 }
 
 static int dummy_inode_mkdir (struct inode *inode, struct dentry *dentry,
-			      int mask)
+			      struct vfsmount *mnt, int mask)
 {
 	return 0;
 }
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2209,7 +2209,8 @@ static int selinux_inode_symlink(struct 
 	return may_create(dir, dentry, SECCLASS_LNK_FILE);
 }
 
-static int selinux_inode_mkdir(struct inode *dir, struct dentry *dentry, int mask)
+static int selinux_inode_mkdir(struct inode *dir, struct dentry *dentry,
+			       struct vfsmount *mnt, int mask)
 {
 	return may_create(dir, dentry, SECCLASS_DIR);
 }

-- 

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

* [AppArmor 09/41] Add a struct vfsmount parameter to vfs_mknod()
  2007-04-12  9:08 [AppArmor 00/41] AppArmor security module overview jjohansen
                   ` (7 preceding siblings ...)
  2007-04-12  9:08 ` [AppArmor 08/41] Pass struct vfsmount to the inode_mkdir LSM hook jjohansen
@ 2007-04-12  9:08 ` jjohansen
  2007-04-12  9:08 ` [AppArmor 10/41] Pass struct vfsmount to the inode_mknod LSM hook jjohansen
                   ` (34 subsequent siblings)
  43 siblings, 0 replies; 187+ messages in thread
From: jjohansen @ 2007-04-12  9:08 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, linux-fsdevel, chrisw, Tony Jones,
	Andreas Gruenbacher, John Johansen

[-- Attachment #1: vfs-mknod.diff --]
[-- Type: text/plain, Size: 3496 bytes --]

The vfsmount will be passed down to the LSM hook so that LSMs can compute
pathnames.

Signed-off-by: Tony Jones <tonyj@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>

---
 fs/ecryptfs/inode.c |    5 ++++-
 fs/namei.c          |   10 ++++++----
 fs/nfsd/vfs.c       |    3 ++-
 include/linux/fs.h  |    2 +-
 net/unix/af_unix.c  |    2 +-
 5 files changed, 14 insertions(+), 8 deletions(-)

--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c
@@ -560,11 +560,14 @@ ecryptfs_mknod(struct inode *dir, struct
 {
 	int rc;
 	struct dentry *lower_dentry;
+	struct vfsmount *lower_mnt;
 	struct dentry *lower_dir_dentry;
 
 	lower_dentry = ecryptfs_dentry_to_lower(dentry);
+	lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry);
 	lower_dir_dentry = lock_parent(lower_dentry);
-	rc = vfs_mknod(lower_dir_dentry->d_inode, lower_dentry, mode, dev);
+	rc = vfs_mknod(lower_dir_dentry->d_inode, lower_dentry, lower_mnt, mode,
+		       dev);
 	if (rc || !lower_dentry->d_inode)
 		goto out;
 	rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb, 0);
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1837,7 +1837,8 @@ fail:
 }
 EXPORT_SYMBOL_GPL(lookup_create);
 
-int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
+int vfs_mknod(struct inode *dir, struct dentry *dentry, struct vfsmount *mnt,
+	      int mode, dev_t dev)
 {
 	int error = may_create(dir, dentry, NULL);
 
@@ -1889,11 +1890,12 @@ asmlinkage long sys_mknodat(int dfd, con
 			error = vfs_create(nd.dentry->d_inode,dentry,mode,&nd);
 			break;
 		case S_IFCHR: case S_IFBLK:
-			error = vfs_mknod(nd.dentry->d_inode,dentry,mode,
-					new_decode_dev(dev));
+			error = vfs_mknod(nd.dentry->d_inode, dentry, nd.mnt,
+					  mode, new_decode_dev(dev));
 			break;
 		case S_IFIFO: case S_IFSOCK:
-			error = vfs_mknod(nd.dentry->d_inode,dentry,mode,0);
+			error = vfs_mknod(nd.dentry->d_inode, dentry, nd.mnt,
+					  mode, 0);
 			break;
 		case S_IFDIR:
 			error = -EPERM;
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -1193,7 +1193,8 @@ nfsd_create(struct svc_rqst *rqstp, stru
 	case S_IFBLK:
 	case S_IFIFO:
 	case S_IFSOCK:
-		host_err = vfs_mknod(dirp, dchild, iap->ia_mode, rdev);
+		host_err = vfs_mknod(dirp, dchild, fhp->fh_export->ex_mnt,
+				     iap->ia_mode, rdev);
 		break;
 	default:
 	        printk("nfsd: bad file type %o in nfsd_create\n", type);
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -981,7 +981,7 @@ extern void unlock_super(struct super_bl
 extern int vfs_permission(struct nameidata *, int);
 extern int vfs_create(struct inode *, struct dentry *, int, struct nameidata *);
 extern int vfs_mkdir(struct inode *, struct dentry *, struct vfsmount *, int);
-extern int vfs_mknod(struct inode *, struct dentry *, int, dev_t);
+extern int vfs_mknod(struct inode *, struct dentry *, struct vfsmount *, int, dev_t);
 extern int vfs_symlink(struct inode *, struct dentry *, const char *, int);
 extern int vfs_link(struct dentry *, struct inode *, struct dentry *);
 extern int vfs_rmdir(struct inode *, struct dentry *);
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -808,7 +808,7 @@ static int unix_bind(struct socket *sock
 		 */
 		mode = S_IFSOCK |
 		       (SOCK_INODE(sock)->i_mode & ~current->fs->umask);
-		err = vfs_mknod(nd.dentry->d_inode, dentry, mode, 0);
+		err = vfs_mknod(nd.dentry->d_inode, dentry, nd.mnt, mode, 0);
 		if (err)
 			goto out_mknod_dput;
 		mutex_unlock(&nd.dentry->d_inode->i_mutex);

-- 

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

* [AppArmor 10/41] Pass struct vfsmount to the inode_mknod LSM hook
  2007-04-12  9:08 [AppArmor 00/41] AppArmor security module overview jjohansen
                   ` (8 preceding siblings ...)
  2007-04-12  9:08 ` [AppArmor 09/41] Add a struct vfsmount parameter to vfs_mknod() jjohansen
@ 2007-04-12  9:08 ` jjohansen
  2007-04-12  9:08 ` [AppArmor 11/41] Add a struct vfsmount parameter to vfs_symlink() jjohansen
                   ` (33 subsequent siblings)
  43 siblings, 0 replies; 187+ messages in thread
From: jjohansen @ 2007-04-12  9:08 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, linux-fsdevel, chrisw, Tony Jones,
	Andreas Gruenbacher, John Johansen

[-- Attachment #1: security-mknod.diff --]
[-- Type: text/plain, Size: 3210 bytes --]

This is needed for computing pathnames in the AppArmor LSM.

Signed-off-by: Tony Jones <tonyj@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>

---
 fs/namei.c               |    2 +-
 include/linux/security.h |    7 +++++--
 security/dummy.c         |    2 +-
 security/selinux/hooks.c |    5 +++--
 4 files changed, 10 insertions(+), 6 deletions(-)

--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1851,7 +1851,7 @@ int vfs_mknod(struct inode *dir, struct 
 	if (!dir->i_op || !dir->i_op->mknod)
 		return -EPERM;
 
-	error = security_inode_mknod(dir, dentry, mode, dev);
+	error = security_inode_mknod(dir, dentry, mnt, mode, dev);
 	if (error)
 		return error;
 
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -323,6 +323,7 @@ struct request_sock;
  *	and not this hook.
  *	@dir contains the inode structure of parent of the new file.
  *	@dentry contains the dentry structure of the new file.
+ *	@mnt is the vfsmount corresponding to @dentry (may be NULL).
  *	@mode contains the mode of the new file.
  *	@dev contains the the device number.
  *	Return 0 if permission is granted.
@@ -1218,7 +1219,7 @@ struct security_operations {
 			    struct vfsmount *mnt, int mode);
 	int (*inode_rmdir) (struct inode *dir, struct dentry *dentry);
 	int (*inode_mknod) (struct inode *dir, struct dentry *dentry,
-	                    int mode, dev_t dev);
+			    struct vfsmount *mnt, int mode, dev_t dev);
 	int (*inode_rename) (struct inode *old_dir, struct dentry *old_dentry,
 	                     struct inode *new_dir, struct dentry *new_dentry);
 	int (*inode_readlink) (struct dentry *dentry);
@@ -1670,11 +1671,12 @@ static inline int security_inode_rmdir (
 
 static inline int security_inode_mknod (struct inode *dir,
 					struct dentry *dentry,
+					struct vfsmount *mnt,
 					int mode, dev_t dev)
 {
 	if (unlikely (IS_PRIVATE (dir)))
 		return 0;
-	return security_ops->inode_mknod (dir, dentry, mode, dev);
+	return security_ops->inode_mknod (dir, dentry, mnt, mode, dev);
 }
 
 static inline int security_inode_rename (struct inode *old_dir,
@@ -2388,6 +2390,7 @@ static inline int security_inode_rmdir (
 
 static inline int security_inode_mknod (struct inode *dir,
 					struct dentry *dentry,
+					struct vfsmount *mnt,
 					int mode, dev_t dev)
 {
 	return 0;
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -299,7 +299,7 @@ static int dummy_inode_rmdir (struct ino
 }
 
 static int dummy_inode_mknod (struct inode *inode, struct dentry *dentry,
-			      int mode, dev_t dev)
+			      struct vfsmount *mnt, int mode, dev_t dev)
 {
 	return 0;
 }
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2220,11 +2220,12 @@ static int selinux_inode_rmdir(struct in
 	return may_link(dir, dentry, MAY_RMDIR);
 }
 
-static int selinux_inode_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
+static int selinux_inode_mknod(struct inode *dir, struct dentry *dentry,
+			       struct vfsmount *mnt, int mode, dev_t dev)
 {
 	int rc;
 
-	rc = secondary_ops->inode_mknod(dir, dentry, mode, dev);
+	rc = secondary_ops->inode_mknod(dir, dentry, mnt, mode, dev);
 	if (rc)
 		return rc;
 

-- 

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

* [AppArmor 11/41] Add a struct vfsmount parameter to vfs_symlink()
  2007-04-12  9:08 [AppArmor 00/41] AppArmor security module overview jjohansen
                   ` (9 preceding siblings ...)
  2007-04-12  9:08 ` [AppArmor 10/41] Pass struct vfsmount to the inode_mknod LSM hook jjohansen
@ 2007-04-12  9:08 ` jjohansen
  2007-04-12  9:08 ` [AppArmor 12/41] Pass struct vfsmount to the inode_symlink LSM hook jjohansen
                   ` (32 subsequent siblings)
  43 siblings, 0 replies; 187+ messages in thread
From: jjohansen @ 2007-04-12  9:08 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, linux-fsdevel, chrisw, Tony Jones,
	Andreas Gruenbacher, John Johansen

[-- Attachment #1: vfs-symlink.diff --]
[-- Type: text/plain, Size: 3848 bytes --]

The vfsmount will be passed down to the LSM hook so that LSMs can compute
pathnames.

Signed-off-by: Tony Jones <tonyj@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>

---
 fs/ecryptfs/inode.c |    4 +++-
 fs/namei.c          |    6 ++++--
 fs/nfsd/vfs.c       |    7 +++++--
 include/linux/fs.h  |    2 +-
 4 files changed, 13 insertions(+), 6 deletions(-)

--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c
@@ -470,6 +470,7 @@ static int ecryptfs_symlink(struct inode
 {
 	int rc;
 	struct dentry *lower_dentry;
+	struct vfsmount *lower_mnt;
 	struct dentry *lower_dir_dentry;
 	umode_t mode;
 	char *encoded_symname;
@@ -478,6 +479,7 @@ static int ecryptfs_symlink(struct inode
 
 	lower_dentry = ecryptfs_dentry_to_lower(dentry);
 	dget(lower_dentry);
+	lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry);
 	lower_dir_dentry = lock_parent(lower_dentry);
 	mode = S_IALLUGO;
 	encoded_symlen = ecryptfs_encode_filename(crypt_stat, symname,
@@ -487,7 +489,7 @@ static int ecryptfs_symlink(struct inode
 		rc = encoded_symlen;
 		goto out_lock;
 	}
-	rc = vfs_symlink(lower_dir_dentry->d_inode, lower_dentry,
+	rc = vfs_symlink(lower_dir_dentry->d_inode, lower_dentry, lower_mnt,
 			 encoded_symname, mode);
 	kfree(encoded_symname);
 	if (rc || !lower_dentry->d_inode)
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2185,7 +2185,8 @@ asmlinkage long sys_unlink(const char __
 	return do_unlinkat(AT_FDCWD, pathname);
 }
 
-int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname, int mode)
+int vfs_symlink(struct inode *dir, struct dentry *dentry, struct vfsmount *mnt,
+		const char *oldname, int mode)
 {
 	int error = may_create(dir, dentry, NULL);
 
@@ -2231,7 +2232,8 @@ asmlinkage long sys_symlinkat(const char
 	if (IS_ERR(dentry))
 		goto out_unlock;
 
-	error = vfs_symlink(nd.dentry->d_inode, dentry, from, S_IALLUGO);
+	error = vfs_symlink(nd.dentry->d_inode, dentry, nd.mnt, from,
+			    S_IALLUGO);
 	dput(dentry);
 out_unlock:
 	mutex_unlock(&nd.dentry->d_inode->i_mutex);
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -1435,6 +1435,7 @@ nfsd_symlink(struct svc_rqst *rqstp, str
 				struct iattr *iap)
 {
 	struct dentry	*dentry, *dnew;
+	struct vfsmount *mnt;
 	__be32		err, cerr;
 	int		host_err;
 	umode_t		mode;
@@ -1461,6 +1462,7 @@ nfsd_symlink(struct svc_rqst *rqstp, str
 	if (iap && (iap->ia_valid & ATTR_MODE))
 		mode = iap->ia_mode & S_IALLUGO;
 
+	mnt = fhp->fh_export->ex_mnt;
 	if (unlikely(path[plen] != 0)) {
 		char *path_alloced = kmalloc(plen+1, GFP_KERNEL);
 		if (path_alloced == NULL)
@@ -1468,11 +1470,12 @@ nfsd_symlink(struct svc_rqst *rqstp, str
 		else {
 			strncpy(path_alloced, path, plen);
 			path_alloced[plen] = 0;
-			host_err = vfs_symlink(dentry->d_inode, dnew, path_alloced, mode);
+			host_err = vfs_symlink(dentry->d_inode, dnew, mnt,
+					       path_alloced, mode);
 			kfree(path_alloced);
 		}
 	} else
-		host_err = vfs_symlink(dentry->d_inode, dnew, path, mode);
+		host_err = vfs_symlink(dentry->d_inode, dnew, mnt, path, mode);
 
 	if (!host_err) {
 		if (EX_ISSYNC(fhp->fh_export))
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -982,7 +982,7 @@ extern int vfs_permission(struct nameida
 extern int vfs_create(struct inode *, struct dentry *, int, struct nameidata *);
 extern int vfs_mkdir(struct inode *, struct dentry *, struct vfsmount *, int);
 extern int vfs_mknod(struct inode *, struct dentry *, struct vfsmount *, int, dev_t);
-extern int vfs_symlink(struct inode *, struct dentry *, const char *, int);
+extern int vfs_symlink(struct inode *, struct dentry *, struct vfsmount *, const char *, int);
 extern int vfs_link(struct dentry *, struct inode *, struct dentry *);
 extern int vfs_rmdir(struct inode *, struct dentry *);
 extern int vfs_unlink(struct inode *, struct dentry *);

-- 

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

* [AppArmor 12/41] Pass struct vfsmount to the inode_symlink LSM hook
  2007-04-12  9:08 [AppArmor 00/41] AppArmor security module overview jjohansen
                   ` (10 preceding siblings ...)
  2007-04-12  9:08 ` [AppArmor 11/41] Add a struct vfsmount parameter to vfs_symlink() jjohansen
@ 2007-04-12  9:08 ` jjohansen
  2007-04-12  9:08 ` [AppArmor 13/41] Pass struct vfsmount to the inode_readlink " jjohansen
                   ` (31 subsequent siblings)
  43 siblings, 0 replies; 187+ messages in thread
From: jjohansen @ 2007-04-12  9:08 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, linux-fsdevel, chrisw, Tony Jones,
	Andreas Gruenbacher, John Johansen

[-- Attachment #1: security-symlink.diff --]
[-- Type: text/plain, Size: 3260 bytes --]

This is needed for computing pathnames in the AppArmor LSM.

Signed-off-by: Tony Jones <tonyj@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>

---
 fs/namei.c               |    2 +-
 include/linux/security.h |    9 ++++++---
 security/dummy.c         |    2 +-
 security/selinux/hooks.c |    3 ++-
 4 files changed, 10 insertions(+), 6 deletions(-)

--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2196,7 +2196,7 @@ int vfs_symlink(struct inode *dir, struc
 	if (!dir->i_op || !dir->i_op->symlink)
 		return -EPERM;
 
-	error = security_inode_symlink(dir, dentry, oldname);
+	error = security_inode_symlink(dir, dentry, mnt, oldname);
 	if (error)
 		return error;
 
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -301,6 +301,7 @@ struct request_sock;
  *	Check the permission to create a symbolic link to a file.
  *	@dir contains the inode structure of parent directory of the symbolic link.
  *	@dentry contains the dentry structure of the symbolic link.
+ *	@mnt is the vfsmount corresponding to @dentry (may be NULL).
  *	@old_name contains the pathname of file.
  *	Return 0 if permission is granted.
  * @inode_mkdir:
@@ -1213,8 +1214,8 @@ struct security_operations {
 	int (*inode_link) (struct dentry *old_dentry,
 	                   struct inode *dir, struct dentry *new_dentry);
 	int (*inode_unlink) (struct inode *dir, struct dentry *dentry);
-	int (*inode_symlink) (struct inode *dir,
-	                      struct dentry *dentry, const char *old_name);
+	int (*inode_symlink) (struct inode *dir, struct dentry *dentry,
+			      struct vfsmount *mnt, const char *old_name);
 	int (*inode_mkdir) (struct inode *dir, struct dentry *dentry,
 			    struct vfsmount *mnt, int mode);
 	int (*inode_rmdir) (struct inode *dir, struct dentry *dentry);
@@ -1644,11 +1645,12 @@ static inline int security_inode_unlink 
 
 static inline int security_inode_symlink (struct inode *dir,
 					  struct dentry *dentry,
+					  struct vfsmount *mnt,
 					  const char *old_name)
 {
 	if (unlikely (IS_PRIVATE (dir)))
 		return 0;
-	return security_ops->inode_symlink (dir, dentry, old_name);
+	return security_ops->inode_symlink (dir, dentry, mnt, old_name);
 }
 
 static inline int security_inode_mkdir (struct inode *dir,
@@ -2369,6 +2371,7 @@ static inline int security_inode_unlink 
 
 static inline int security_inode_symlink (struct inode *dir,
 					  struct dentry *dentry,
+					  struct vfsmount *mnt,
 					  const char *old_name)
 {
 	return 0;
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -282,7 +282,7 @@ static int dummy_inode_unlink (struct in
 }
 
 static int dummy_inode_symlink (struct inode *inode, struct dentry *dentry,
-				const char *name)
+				struct vfsmount *mnt, const char *name)
 {
 	return 0;
 }
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2204,7 +2204,8 @@ static int selinux_inode_unlink(struct i
 	return may_link(dir, dentry, MAY_UNLINK);
 }
 
-static int selinux_inode_symlink(struct inode *dir, struct dentry *dentry, const char *name)
+static int selinux_inode_symlink(struct inode *dir, struct dentry *dentry,
+				 struct vfsmount *mnt, const char *name)
 {
 	return may_create(dir, dentry, SECCLASS_LNK_FILE);
 }

-- 

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

* [AppArmor 13/41] Pass struct vfsmount to the inode_readlink LSM hook
  2007-04-12  9:08 [AppArmor 00/41] AppArmor security module overview jjohansen
                   ` (11 preceding siblings ...)
  2007-04-12  9:08 ` [AppArmor 12/41] Pass struct vfsmount to the inode_symlink LSM hook jjohansen
@ 2007-04-12  9:08 ` jjohansen
  2007-04-12  9:08 ` [AppArmor 14/41] Add struct vfsmount parameters to vfs_link() jjohansen
                   ` (30 subsequent siblings)
  43 siblings, 0 replies; 187+ messages in thread
From: jjohansen @ 2007-04-12  9:08 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, linux-fsdevel, chrisw, Tony Jones,
	Andreas Gruenbacher, John Johansen

[-- Attachment #1: security-readlink.diff --]
[-- Type: text/plain, Size: 3282 bytes --]

This is needed for computing pathnames in the AppArmor LSM.

Signed-off-by: Tony Jones <tonyj@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>

---
 fs/stat.c                |    2 +-
 include/linux/security.h |   11 +++++++----
 security/dummy.c         |    2 +-
 security/selinux/hooks.c |    2 +-
 4 files changed, 10 insertions(+), 7 deletions(-)

--- a/fs/stat.c
+++ b/fs/stat.c
@@ -307,7 +307,7 @@ asmlinkage long sys_readlinkat(int dfd, 
 
 		error = -EINVAL;
 		if (inode->i_op && inode->i_op->readlink) {
-			error = security_inode_readlink(nd.dentry);
+			error = security_inode_readlink(nd.dentry, nd.mnt);
 			if (!error) {
 				touch_atime(nd.mnt, nd.dentry);
 				error = inode->i_op->readlink(nd.dentry, buf, bufsiz);
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -338,6 +338,7 @@ struct request_sock;
  * @inode_readlink:
  *	Check the permission to read the symbolic link.
  *	@dentry contains the dentry structure for the file link.
+ *	@mnt is the vfsmount corresponding to @dentry (may be NULL).
  *	Return 0 if permission is granted.
  * @inode_follow_link:
  *	Check permission to follow a symbolic link when looking up a pathname.
@@ -1223,7 +1224,7 @@ struct security_operations {
 			    struct vfsmount *mnt, int mode, dev_t dev);
 	int (*inode_rename) (struct inode *old_dir, struct dentry *old_dentry,
 	                     struct inode *new_dir, struct dentry *new_dentry);
-	int (*inode_readlink) (struct dentry *dentry);
+	int (*inode_readlink) (struct dentry *dentry, struct vfsmount *mnt);
 	int (*inode_follow_link) (struct dentry *dentry, struct nameidata *nd);
 	int (*inode_permission) (struct inode *inode, int mask, struct nameidata *nd);
 	int (*inode_setattr) (struct dentry *dentry, struct vfsmount *mnt,
@@ -1693,11 +1694,12 @@ static inline int security_inode_rename 
 					   new_dir, new_dentry);
 }
 
-static inline int security_inode_readlink (struct dentry *dentry)
+static inline int security_inode_readlink (struct dentry *dentry,
+					   struct vfsmount *mnt)
 {
 	if (unlikely (IS_PRIVATE (dentry->d_inode)))
 		return 0;
-	return security_ops->inode_readlink (dentry);
+	return security_ops->inode_readlink (dentry, mnt);
 }
 
 static inline int security_inode_follow_link (struct dentry *dentry,
@@ -2407,7 +2409,8 @@ static inline int security_inode_rename 
 	return 0;
 }
 
-static inline int security_inode_readlink (struct dentry *dentry)
+static inline int security_inode_readlink (struct dentry *dentry,
+					   struct vfsmount *mnt)
 {
 	return 0;
 }
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -312,7 +312,7 @@ static int dummy_inode_rename (struct in
 	return 0;
 }
 
-static int dummy_inode_readlink (struct dentry *dentry)
+static int dummy_inode_readlink (struct dentry *dentry, struct vfsmount *mnt)
 {
 	return 0;
 }
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2239,7 +2239,7 @@ static int selinux_inode_rename(struct i
 	return may_rename(old_inode, old_dentry, new_inode, new_dentry);
 }
 
-static int selinux_inode_readlink(struct dentry *dentry)
+static int selinux_inode_readlink(struct dentry *dentry, struct vfsmount *mnt)
 {
 	return dentry_has_perm(current, NULL, dentry, FILE__READ);
 }

-- 

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

* [AppArmor 14/41] Add struct vfsmount parameters to vfs_link()
  2007-04-12  9:08 [AppArmor 00/41] AppArmor security module overview jjohansen
                   ` (12 preceding siblings ...)
  2007-04-12  9:08 ` [AppArmor 13/41] Pass struct vfsmount to the inode_readlink " jjohansen
@ 2007-04-12  9:08 ` jjohansen
  2007-04-12  9:08 ` [AppArmor 15/41] Pass the struct vfsmounts to the inode_link LSM hook jjohansen
                   ` (29 subsequent siblings)
  43 siblings, 0 replies; 187+ messages in thread
From: jjohansen @ 2007-04-12  9:08 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, linux-fsdevel, chrisw, Tony Jones,
	Andreas Gruenbacher, John Johansen

[-- Attachment #1: vfs-link.diff --]
[-- Type: text/plain, Size: 3494 bytes --]

The vfsmount will be passed down to the LSM hook so that LSMs can compute
pathnames.

Signed-off-by: Tony Jones <tonyj@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>

---
 fs/ecryptfs/inode.c |    9 +++++++--
 fs/namei.c          |    5 +++--
 fs/nfsd/vfs.c       |    3 ++-
 include/linux/fs.h  |    2 +-
 4 files changed, 13 insertions(+), 6 deletions(-)

--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c
@@ -411,19 +411,24 @@ static int ecryptfs_link(struct dentry *
 			 struct dentry *new_dentry)
 {
 	struct dentry *lower_old_dentry;
+	struct vfsmount *lower_old_mnt;
 	struct dentry *lower_new_dentry;
+	struct vfsmount *lower_new_mnt;
 	struct dentry *lower_dir_dentry;
 	u64 file_size_save;
 	int rc;
 
 	file_size_save = i_size_read(old_dentry->d_inode);
 	lower_old_dentry = ecryptfs_dentry_to_lower(old_dentry);
+	lower_old_mnt = ecryptfs_dentry_to_lower_mnt(old_dentry);
 	lower_new_dentry = ecryptfs_dentry_to_lower(new_dentry);
+	lower_new_mnt = ecryptfs_dentry_to_lower_mnt(new_dentry);
 	dget(lower_old_dentry);
 	dget(lower_new_dentry);
 	lower_dir_dentry = lock_parent(lower_new_dentry);
-	rc = vfs_link(lower_old_dentry, lower_dir_dentry->d_inode,
-		      lower_new_dentry);
+	rc = vfs_link(lower_old_dentry, lower_old_mnt,
+		      lower_dir_dentry->d_inode, lower_new_dentry,
+		      lower_new_mnt);
 	if (rc || !lower_new_dentry->d_inode)
 		goto out_lock;
 	rc = ecryptfs_interpose(lower_new_dentry, new_dentry, dir->i_sb, 0);
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2250,7 +2250,7 @@ asmlinkage long sys_symlink(const char _
 	return sys_symlinkat(oldname, AT_FDCWD, newname);
 }
 
-int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry)
+int vfs_link(struct dentry *old_dentry, struct vfsmount *old_mnt, struct inode *dir, struct dentry *new_dentry, struct vfsmount *new_mnt)
 {
 	struct inode *inode = old_dentry->d_inode;
 	int error;
@@ -2328,7 +2328,8 @@ asmlinkage long sys_linkat(int olddfd, c
 	error = PTR_ERR(new_dentry);
 	if (IS_ERR(new_dentry))
 		goto out_unlock;
-	error = vfs_link(old_nd.dentry, nd.dentry->d_inode, new_dentry);
+	error = vfs_link(old_nd.dentry, old_nd.mnt, nd.dentry->d_inode,
+			 new_dentry, nd.mnt);
 	dput(new_dentry);
 out_unlock:
 	mutex_unlock(&nd.dentry->d_inode->i_mutex);
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -1534,7 +1534,8 @@ nfsd_link(struct svc_rqst *rqstp, struct
 	dold = tfhp->fh_dentry;
 	dest = dold->d_inode;
 
-	host_err = vfs_link(dold, dirp, dnew);
+	host_err = vfs_link(dold, tfhp->fh_export->ex_mnt, dirp,
+			    dnew, ffhp->fh_export->ex_mnt);
 	if (!host_err) {
 		if (EX_ISSYNC(ffhp->fh_export)) {
 			err = nfserrno(nfsd_sync_dir(ddir));
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -983,7 +983,7 @@ extern int vfs_create(struct inode *, st
 extern int vfs_mkdir(struct inode *, struct dentry *, struct vfsmount *, int);
 extern int vfs_mknod(struct inode *, struct dentry *, struct vfsmount *, int, dev_t);
 extern int vfs_symlink(struct inode *, struct dentry *, struct vfsmount *, const char *, int);
-extern int vfs_link(struct dentry *, struct inode *, struct dentry *);
+extern int vfs_link(struct dentry *, struct vfsmount *, struct inode *, struct dentry *, struct vfsmount *);
 extern int vfs_rmdir(struct inode *, struct dentry *);
 extern int vfs_unlink(struct inode *, struct dentry *);
 extern int vfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *);

-- 

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

* [AppArmor 15/41] Pass the struct vfsmounts to the inode_link LSM hook
  2007-04-12  9:08 [AppArmor 00/41] AppArmor security module overview jjohansen
                   ` (13 preceding siblings ...)
  2007-04-12  9:08 ` [AppArmor 14/41] Add struct vfsmount parameters to vfs_link() jjohansen
@ 2007-04-12  9:08 ` jjohansen
  2007-04-12  9:08 ` [AppArmor 16/41] Add a struct vfsmount parameter to vfs_rmdir() jjohansen
                   ` (28 subsequent siblings)
  43 siblings, 0 replies; 187+ messages in thread
From: jjohansen @ 2007-04-12  9:08 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, linux-fsdevel, chrisw, Tony Jones,
	Andreas Gruenbacher, John Johansen

[-- Attachment #1: security-link.diff --]
[-- Type: text/plain, Size: 4246 bytes --]

This is needed for computing pathnames in the AppArmor LSM.

Signed-off-by: Tony Jones <tonyj@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>

---
 fs/namei.c               |    3 ++-
 include/linux/security.h |   18 +++++++++++++-----
 security/dummy.c         |    6 ++++--
 security/selinux/hooks.c |    9 +++++++--
 4 files changed, 26 insertions(+), 10 deletions(-)

--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2275,7 +2275,8 @@ int vfs_link(struct dentry *old_dentry, 
 	if (S_ISDIR(old_dentry->d_inode->i_mode))
 		return -EPERM;
 
-	error = security_inode_link(old_dentry, dir, new_dentry);
+	error = security_inode_link(old_dentry, old_mnt, dir, new_dentry,
+				    new_mnt);
 	if (error)
 		return error;
 
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -289,8 +289,10 @@ struct request_sock;
  * @inode_link:
  *	Check permission before creating a new hard link to a file.
  *	@old_dentry contains the dentry structure for an existing link to the file.
+ *	@old_mnt is the vfsmount corresponding to @old_dentry (may be NULL).
  *	@dir contains the inode structure of the parent directory of the new link.
  *	@new_dentry contains the dentry structure for the new link.
+ *	@new_mnt is the vfsmount corresponding to @new_dentry (may be NULL).
  *	Return 0 if permission is granted.
  * @inode_unlink:
  *	Check the permission to remove a hard link to a file. 
@@ -1212,8 +1214,9 @@ struct security_operations {
 				    char **name, void **value, size_t *len);
 	int (*inode_create) (struct inode *dir, struct dentry *dentry,
 			     struct vfsmount *mnt, int mode);
-	int (*inode_link) (struct dentry *old_dentry,
-	                   struct inode *dir, struct dentry *new_dentry);
+	int (*inode_link) (struct dentry *old_dentry, struct vfsmount *old_mnt,
+	                   struct inode *dir, struct dentry *new_dentry,
+			   struct vfsmount *new_mnt);
 	int (*inode_unlink) (struct inode *dir, struct dentry *dentry);
 	int (*inode_symlink) (struct inode *dir, struct dentry *dentry,
 			      struct vfsmount *mnt, const char *old_name);
@@ -1628,12 +1631,15 @@ static inline int security_inode_create 
 }
 
 static inline int security_inode_link (struct dentry *old_dentry,
+				       struct vfsmount *old_mnt,
 				       struct inode *dir,
-				       struct dentry *new_dentry)
+				       struct dentry *new_dentry,
+				       struct vfsmount *new_mnt)
 {
 	if (unlikely (IS_PRIVATE (old_dentry->d_inode)))
 		return 0;
-	return security_ops->inode_link (old_dentry, dir, new_dentry);
+	return security_ops->inode_link (old_dentry, old_mnt, dir,
+					 new_dentry, new_mnt);
 }
 
 static inline int security_inode_unlink (struct inode *dir,
@@ -2359,8 +2365,10 @@ static inline int security_inode_create 
 }
 
 static inline int security_inode_link (struct dentry *old_dentry,
+				       struct vfsmount *old_mnt,
 				       struct inode *dir,
-				       struct dentry *new_dentry)
+				       struct dentry *new_dentry,
+				       struct vfsmount *new_mnt)
 {
 	return 0;
 }
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -270,8 +270,10 @@ static int dummy_inode_create (struct in
 	return 0;
 }
 
-static int dummy_inode_link (struct dentry *old_dentry, struct inode *inode,
-			     struct dentry *new_dentry)
+static int dummy_inode_link (struct dentry *old_dentry,
+			     struct vfsmount *old_mnt, struct inode *inode,
+			     struct dentry *new_dentry,
+			     struct vfsmount *new_mnt)
 {
 	return 0;
 }
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2184,11 +2184,16 @@ static int selinux_inode_create(struct i
 	return may_create(dir, dentry, SECCLASS_FILE);
 }
 
-static int selinux_inode_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry)
+static int selinux_inode_link(struct dentry *old_dentry,
+			      struct vfsmount *old_mnt,
+			      struct inode *dir,
+			      struct dentry *new_dentry,
+			      struct vfsmount *new_mnt)
 {
 	int rc;
 
-	rc = secondary_ops->inode_link(old_dentry,dir,new_dentry);
+	rc = secondary_ops->inode_link(old_dentry, old_mnt, dir, new_dentry,
+				       new_mnt);
 	if (rc)
 		return rc;
 	return may_link(dir, old_dentry, MAY_LINK);

-- 

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

* [AppArmor 16/41] Add a struct vfsmount parameter to vfs_rmdir()
  2007-04-12  9:08 [AppArmor 00/41] AppArmor security module overview jjohansen
                   ` (14 preceding siblings ...)
  2007-04-12  9:08 ` [AppArmor 15/41] Pass the struct vfsmounts to the inode_link LSM hook jjohansen
@ 2007-04-12  9:08 ` jjohansen
  2007-04-12  9:08 ` [AppArmor 17/41] Pass struct vfsmount to the inode_rmdir LSM hook jjohansen
                   ` (27 subsequent siblings)
  43 siblings, 0 replies; 187+ messages in thread
From: jjohansen @ 2007-04-12  9:08 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, linux-fsdevel, chrisw, Tony Jones,
	Andreas Gruenbacher, John Johansen

[-- Attachment #1: vfs-rmdir.diff --]
[-- Type: text/plain, Size: 3553 bytes --]

The vfsmount will be passed down to the LSM hook so that LSMs can compute
pathnames.

Signed-off-by: Tony Jones <tonyj@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>

---
 fs/ecryptfs/inode.c   |    4 +++-
 fs/namei.c            |    4 ++--
 fs/nfsd/nfs4recover.c |    2 +-
 fs/nfsd/vfs.c         |    2 +-
 fs/reiserfs/xattr.c   |    2 +-
 include/linux/fs.h    |    2 +-
 6 files changed, 9 insertions(+), 7 deletions(-)

--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c
@@ -542,14 +542,16 @@ out:
 static int ecryptfs_rmdir(struct inode *dir, struct dentry *dentry)
 {
 	struct dentry *lower_dentry;
+	struct vfsmount *lower_mnt;
 	struct dentry *lower_dir_dentry;
 	int rc;
 
 	lower_dentry = ecryptfs_dentry_to_lower(dentry);
+	lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry);
 	dget(dentry);
 	lower_dir_dentry = lock_parent(lower_dentry);
 	dget(lower_dentry);
-	rc = vfs_rmdir(lower_dir_dentry->d_inode, lower_dentry);
+	rc = vfs_rmdir(lower_dir_dentry->d_inode, lower_dentry, lower_mnt);
 	dput(lower_dentry);
 	if (!rc)
 		d_delete(lower_dentry);
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2006,7 +2006,7 @@ void dentry_unhash(struct dentry *dentry
 	spin_unlock(&dcache_lock);
 }
 
-int vfs_rmdir(struct inode *dir, struct dentry *dentry)
+int vfs_rmdir(struct inode *dir, struct dentry *dentry,struct vfsmount *mnt)
 {
 	int error = may_delete(dir, dentry, 1);
 
@@ -2070,7 +2070,7 @@ static long do_rmdir(int dfd, const char
 	error = PTR_ERR(dentry);
 	if (IS_ERR(dentry))
 		goto exit2;
-	error = vfs_rmdir(nd.dentry->d_inode, dentry);
+	error = vfs_rmdir(nd.dentry->d_inode, dentry, nd.mnt);
 	dput(dentry);
 exit2:
 	mutex_unlock(&nd.dentry->d_inode->i_mutex);
--- a/fs/nfsd/nfs4recover.c
+++ b/fs/nfsd/nfs4recover.c
@@ -276,7 +276,7 @@ nfsd4_clear_clid_dir(struct dentry *dir,
 	 * a kernel from the future.... */
 	nfsd4_list_rec_dir(dentry, nfsd4_remove_clid_file);
 	mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT);
-	status = vfs_rmdir(dir->d_inode, dentry);
+	status = vfs_rmdir(dir->d_inode, dentry, rec_dir.mnt);
 	mutex_unlock(&dir->d_inode->i_mutex);
 	return status;
 }
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -1702,7 +1702,7 @@ nfsd_unlink(struct svc_rqst *rqstp, stru
 #endif
 		host_err = vfs_unlink(dirp, rdentry);
 	} else { /* It's RMDIR */
-		host_err = vfs_rmdir(dirp, rdentry);
+		host_err = vfs_rmdir(dirp, rdentry, fhp->fh_export->ex_mnt);
 	}
 
 	dput(rdentry);
--- a/fs/reiserfs/xattr.c
+++ b/fs/reiserfs/xattr.c
@@ -823,7 +823,7 @@ int reiserfs_delete_xattrs(struct inode 
 	if (dir->d_inode->i_nlink <= 2) {
 		root = get_xa_root(inode->i_sb);
 		reiserfs_write_lock_xattrs(inode->i_sb);
-		err = vfs_rmdir(root->d_inode, dir);
+		err = vfs_rmdir(root->d_inode, dir, NULL);
 		reiserfs_write_unlock_xattrs(inode->i_sb);
 		dput(root);
 	} else {
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -984,7 +984,7 @@ extern int vfs_mkdir(struct inode *, str
 extern int vfs_mknod(struct inode *, struct dentry *, struct vfsmount *, int, dev_t);
 extern int vfs_symlink(struct inode *, struct dentry *, struct vfsmount *, const char *, int);
 extern int vfs_link(struct dentry *, struct vfsmount *, struct inode *, struct dentry *, struct vfsmount *);
-extern int vfs_rmdir(struct inode *, struct dentry *);
+extern int vfs_rmdir(struct inode *, struct dentry *, struct vfsmount *);
 extern int vfs_unlink(struct inode *, struct dentry *);
 extern int vfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *);
 

-- 

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

* [AppArmor 17/41] Pass struct vfsmount to the inode_rmdir LSM hook
  2007-04-12  9:08 [AppArmor 00/41] AppArmor security module overview jjohansen
                   ` (15 preceding siblings ...)
  2007-04-12  9:08 ` [AppArmor 16/41] Add a struct vfsmount parameter to vfs_rmdir() jjohansen
@ 2007-04-12  9:08 ` jjohansen
  2007-04-12  9:08 ` [AppArmor 18/41] call lsm hook before unhashing dentry in vfs_rmdir() jjohansen
                   ` (26 subsequent siblings)
  43 siblings, 0 replies; 187+ messages in thread
From: jjohansen @ 2007-04-12  9:08 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, linux-fsdevel, chrisw, Tony Jones,
	Andreas Gruenbacher, John Johansen

[-- Attachment #1: security-rmdir.diff --]
[-- Type: text/plain, Size: 3218 bytes --]

This is needed for computing pathnames in the AppArmor LSM.

Signed-off-by: Tony Jones <tonyj@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>

---
 fs/namei.c               |    2 +-
 include/linux/security.h |   12 ++++++++----
 security/dummy.c         |    3 ++-
 security/selinux/hooks.c |    3 ++-
 4 files changed, 13 insertions(+), 7 deletions(-)

--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2023,7 +2023,7 @@ int vfs_rmdir(struct inode *dir, struct 
 	if (d_mountpoint(dentry))
 		error = -EBUSY;
 	else {
-		error = security_inode_rmdir(dir, dentry);
+		error = security_inode_rmdir(dir, dentry, mnt);
 		if (!error) {
 			error = dir->i_op->rmdir(dir, dentry);
 			if (!error)
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -318,6 +318,7 @@ struct request_sock;
  *	Check the permission to remove a directory.
  *	@dir contains the inode structure of parent of the directory to be removed.
  *	@dentry contains the dentry structure of directory to be removed.
+ *	@mnt is the vfsmount corresponding to @dentry (may be NULL).
  *	Return 0 if permission is granted.
  * @inode_mknod:
  *	Check permissions when creating a special file (or a socket or a fifo
@@ -1222,7 +1223,8 @@ struct security_operations {
 			      struct vfsmount *mnt, const char *old_name);
 	int (*inode_mkdir) (struct inode *dir, struct dentry *dentry,
 			    struct vfsmount *mnt, int mode);
-	int (*inode_rmdir) (struct inode *dir, struct dentry *dentry);
+	int (*inode_rmdir) (struct inode *dir, struct dentry *dentry,
+			    struct vfsmount *mnt);
 	int (*inode_mknod) (struct inode *dir, struct dentry *dentry,
 			    struct vfsmount *mnt, int mode, dev_t dev);
 	int (*inode_rename) (struct inode *old_dir, struct dentry *old_dentry,
@@ -1671,11 +1673,12 @@ static inline int security_inode_mkdir (
 }
 
 static inline int security_inode_rmdir (struct inode *dir,
-					struct dentry *dentry)
+					struct dentry *dentry,
+					struct vfsmount *mnt)
 {
 	if (unlikely (IS_PRIVATE (dentry->d_inode)))
 		return 0;
-	return security_ops->inode_rmdir (dir, dentry);
+	return security_ops->inode_rmdir (dir, dentry, mnt);
 }
 
 static inline int security_inode_mknod (struct inode *dir,
@@ -2396,7 +2399,8 @@ static inline int security_inode_mkdir (
 }
 
 static inline int security_inode_rmdir (struct inode *dir,
-					struct dentry *dentry)
+					struct dentry *dentry,
+					struct vfsmount *mnt)
 {
 	return 0;
 }
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -295,7 +295,8 @@ static int dummy_inode_mkdir (struct ino
 	return 0;
 }
 
-static int dummy_inode_rmdir (struct inode *inode, struct dentry *dentry)
+static int dummy_inode_rmdir (struct inode *inode, struct dentry *dentry,
+			      struct vfsmount *mnt)
 {
 	return 0;
 }
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2221,7 +2221,8 @@ static int selinux_inode_mkdir(struct in
 	return may_create(dir, dentry, SECCLASS_DIR);
 }
 
-static int selinux_inode_rmdir(struct inode *dir, struct dentry *dentry)
+static int selinux_inode_rmdir(struct inode *dir, struct dentry *dentry,
+			       struct vfsmount *mnt)
 {
 	return may_link(dir, dentry, MAY_RMDIR);
 }

-- 

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

* [AppArmor 18/41] call lsm hook before unhashing dentry in vfs_rmdir()
  2007-04-12  9:08 [AppArmor 00/41] AppArmor security module overview jjohansen
                   ` (16 preceding siblings ...)
  2007-04-12  9:08 ` [AppArmor 17/41] Pass struct vfsmount to the inode_rmdir LSM hook jjohansen
@ 2007-04-12  9:08 ` jjohansen
  2007-04-12  9:08 ` [AppArmor 19/41] Add a struct vfsmount parameter to vfs_unlink() jjohansen
                   ` (25 subsequent siblings)
  43 siblings, 0 replies; 187+ messages in thread
From: jjohansen @ 2007-04-12  9:08 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, linux-fsdevel, chrisw, John Johansen,
	Andreas Gruenbacher

[-- Attachment #1: fix-vfs_rmdir.diff --]
[-- Type: text/plain, Size: 1172 bytes --]

If we unhash the dentry before calling the security_inode_rmdir hook,
we cannot compute the file's pathname in the hook anymore. AppArmor
needs to know the filename in order to decide whether a file may be
deleted, though.

Signed-off-by: John Johansen <jjohansen@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>

---
 fs/namei.c |   13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2016,6 +2016,10 @@ int vfs_rmdir(struct inode *dir, struct 
 	if (!dir->i_op || !dir->i_op->rmdir)
 		return -EPERM;
 
+	error = security_inode_rmdir(dir, dentry, mnt);
+	if (error)
+		return error;
+
 	DQUOT_INIT(dir);
 
 	mutex_lock(&dentry->d_inode->i_mutex);
@@ -2023,12 +2027,9 @@ int vfs_rmdir(struct inode *dir, struct 
 	if (d_mountpoint(dentry))
 		error = -EBUSY;
 	else {
-		error = security_inode_rmdir(dir, dentry, mnt);
-		if (!error) {
-			error = dir->i_op->rmdir(dir, dentry);
-			if (!error)
-				dentry->d_inode->i_flags |= S_DEAD;
-		}
+		error = dir->i_op->rmdir(dir, dentry);
+		if (!error)
+			dentry->d_inode->i_flags |= S_DEAD;
 	}
 	mutex_unlock(&dentry->d_inode->i_mutex);
 	if (!error) {

-- 

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

* [AppArmor 19/41] Add a struct vfsmount parameter to vfs_unlink()
  2007-04-12  9:08 [AppArmor 00/41] AppArmor security module overview jjohansen
                   ` (17 preceding siblings ...)
  2007-04-12  9:08 ` [AppArmor 18/41] call lsm hook before unhashing dentry in vfs_rmdir() jjohansen
@ 2007-04-12  9:08 ` jjohansen
  2007-04-12  9:08 ` [AppArmor 20/41] Pass struct vfsmount to the inode_unlink LSM hook jjohansen
                   ` (24 subsequent siblings)
  43 siblings, 0 replies; 187+ messages in thread
From: jjohansen @ 2007-04-12  9:08 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, linux-fsdevel, chrisw, Tony Jones,
	Andreas Gruenbacher, John Johansen

[-- Attachment #1: vfs-unlink.diff --]
[-- Type: text/plain, Size: 3287 bytes --]

The vfsmount will be passed down to the LSM hook so that LSMs can compute
pathnames.

Signed-off-by: Tony Jones <tonyj@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>

---
 fs/ecryptfs/inode.c   |    3 ++-
 fs/namei.c            |    4 ++--
 fs/nfsd/nfs4recover.c |    2 +-
 fs/nfsd/vfs.c         |    2 +-
 include/linux/fs.h    |    2 +-
 ipc/mqueue.c          |    2 +-
 6 files changed, 8 insertions(+), 7 deletions(-)

--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c
@@ -453,10 +453,11 @@ static int ecryptfs_unlink(struct inode 
 {
 	int rc = 0;
 	struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
+	struct vfsmount *lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry);
 	struct inode *lower_dir_inode = ecryptfs_inode_to_lower(dir);
 
 	lock_parent(lower_dentry);
-	rc = vfs_unlink(lower_dir_inode, lower_dentry);
+	rc = vfs_unlink(lower_dir_inode, lower_dentry, lower_mnt);
 	if (rc) {
 		printk(KERN_ERR "Error in vfs_unlink; rc = [%d]\n", rc);
 		goto out_unlock;
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2087,7 +2087,7 @@ asmlinkage long sys_rmdir(const char __u
 	return do_rmdir(AT_FDCWD, pathname);
 }
 
-int vfs_unlink(struct inode *dir, struct dentry *dentry)
+int vfs_unlink(struct inode *dir, struct dentry *dentry, struct vfsmount *mnt)
 {
 	int error = may_delete(dir, dentry, 0);
 
@@ -2151,7 +2151,7 @@ static long do_unlinkat(int dfd, const c
 		inode = dentry->d_inode;
 		if (inode)
 			atomic_inc(&inode->i_count);
-		error = vfs_unlink(nd.dentry->d_inode, dentry);
+		error = vfs_unlink(nd.dentry->d_inode, dentry, nd.mnt);
 	exit2:
 		dput(dentry);
 	}
--- a/fs/nfsd/nfs4recover.c
+++ b/fs/nfsd/nfs4recover.c
@@ -261,7 +261,7 @@ nfsd4_remove_clid_file(struct dentry *di
 		return -EINVAL;
 	}
 	mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT);
-	status = vfs_unlink(dir->d_inode, dentry);
+	status = vfs_unlink(dir->d_inode, dentry, rec_dir.mnt);
 	mutex_unlock(&dir->d_inode->i_mutex);
 	return status;
 }
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -1700,7 +1700,7 @@ nfsd_unlink(struct svc_rqst *rqstp, stru
 			host_err = -EPERM;
 		} else
 #endif
-		host_err = vfs_unlink(dirp, rdentry);
+		host_err = vfs_unlink(dirp, rdentry, fhp->fh_export->ex_mnt);
 	} else { /* It's RMDIR */
 		host_err = vfs_rmdir(dirp, rdentry, fhp->fh_export->ex_mnt);
 	}
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -985,7 +985,7 @@ extern int vfs_mknod(struct inode *, str
 extern int vfs_symlink(struct inode *, struct dentry *, struct vfsmount *, const char *, int);
 extern int vfs_link(struct dentry *, struct vfsmount *, struct inode *, struct dentry *, struct vfsmount *);
 extern int vfs_rmdir(struct inode *, struct dentry *, struct vfsmount *);
-extern int vfs_unlink(struct inode *, struct dentry *);
+extern int vfs_unlink(struct inode *, struct dentry *, struct vfsmount *);
 extern int vfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *);
 
 /*
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -748,7 +748,7 @@ asmlinkage long sys_mq_unlink(const char
 	if (inode)
 		atomic_inc(&inode->i_count);
 
-	err = vfs_unlink(dentry->d_parent->d_inode, dentry);
+	err = vfs_unlink(dentry->d_parent->d_inode, dentry, mqueue_mnt);
 out_err:
 	dput(dentry);
 

-- 

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

* [AppArmor 20/41] Pass struct vfsmount to the inode_unlink LSM hook
  2007-04-12  9:08 [AppArmor 00/41] AppArmor security module overview jjohansen
                   ` (18 preceding siblings ...)
  2007-04-12  9:08 ` [AppArmor 19/41] Add a struct vfsmount parameter to vfs_unlink() jjohansen
@ 2007-04-12  9:08 ` jjohansen
  2007-04-12  9:08 ` [AppArmor 21/41] Add struct vfsmount parameters to vfs_rename() jjohansen
                   ` (23 subsequent siblings)
  43 siblings, 0 replies; 187+ messages in thread
From: jjohansen @ 2007-04-12  9:08 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, linux-fsdevel, chrisw, Tony Jones,
	Andreas Gruenbacher, John Johansen

[-- Attachment #1: security-unlink.diff --]
[-- Type: text/plain, Size: 3367 bytes --]

This is needed for computing pathnames in the AppArmor LSM.

Signed-off-by: Tony Jones <tonyj@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>

---
 fs/namei.c               |    2 +-
 include/linux/security.h |   12 ++++++++----
 security/dummy.c         |    3 ++-
 security/selinux/hooks.c |    5 +++--
 4 files changed, 14 insertions(+), 8 deletions(-)

--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2103,7 +2103,7 @@ int vfs_unlink(struct inode *dir, struct
 	if (d_mountpoint(dentry))
 		error = -EBUSY;
 	else {
-		error = security_inode_unlink(dir, dentry);
+		error = security_inode_unlink(dir, dentry, mnt);
 		if (!error)
 			error = dir->i_op->unlink(dir, dentry);
 	}
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -298,6 +298,7 @@ struct request_sock;
  *	Check the permission to remove a hard link to a file. 
  *	@dir contains the inode structure of parent directory of the file.
  *	@dentry contains the dentry structure for file to be unlinked.
+ *	@mnt is the vfsmount corresponding to @dentry (may be NULL).
  *	Return 0 if permission is granted.
  * @inode_symlink:
  *	Check the permission to create a symbolic link to a file.
@@ -1218,7 +1219,8 @@ struct security_operations {
 	int (*inode_link) (struct dentry *old_dentry, struct vfsmount *old_mnt,
 	                   struct inode *dir, struct dentry *new_dentry,
 			   struct vfsmount *new_mnt);
-	int (*inode_unlink) (struct inode *dir, struct dentry *dentry);
+	int (*inode_unlink) (struct inode *dir, struct dentry *dentry,
+			     struct vfsmount *mnt);
 	int (*inode_symlink) (struct inode *dir, struct dentry *dentry,
 			      struct vfsmount *mnt, const char *old_name);
 	int (*inode_mkdir) (struct inode *dir, struct dentry *dentry,
@@ -1645,11 +1647,12 @@ static inline int security_inode_link (s
 }
 
 static inline int security_inode_unlink (struct inode *dir,
-					 struct dentry *dentry)
+					 struct dentry *dentry,
+					 struct vfsmount *mnt)
 {
 	if (unlikely (IS_PRIVATE (dentry->d_inode)))
 		return 0;
-	return security_ops->inode_unlink (dir, dentry);
+	return security_ops->inode_unlink (dir, dentry, mnt);
 }
 
 static inline int security_inode_symlink (struct inode *dir,
@@ -2377,7 +2380,8 @@ static inline int security_inode_link (s
 }
 
 static inline int security_inode_unlink (struct inode *dir,
-					 struct dentry *dentry)
+					 struct dentry *dentry,
+					 struct vfsmount *mnt)
 {
 	return 0;
 }
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -278,7 +278,8 @@ static int dummy_inode_link (struct dent
 	return 0;
 }
 
-static int dummy_inode_unlink (struct inode *inode, struct dentry *dentry)
+static int dummy_inode_unlink (struct inode *inode, struct dentry *dentry,
+			       struct vfsmount *mnt)
 {
 	return 0;
 }
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2199,11 +2199,12 @@ static int selinux_inode_link(struct den
 	return may_link(dir, old_dentry, MAY_LINK);
 }
 
-static int selinux_inode_unlink(struct inode *dir, struct dentry *dentry)
+static int selinux_inode_unlink(struct inode *dir, struct dentry *dentry,
+			        struct vfsmount *mnt)
 {
 	int rc;
 
-	rc = secondary_ops->inode_unlink(dir, dentry);
+	rc = secondary_ops->inode_unlink(dir, dentry, mnt);
 	if (rc)
 		return rc;
 	return may_link(dir, dentry, MAY_UNLINK);

-- 

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

* [AppArmor 21/41] Add struct vfsmount parameters to vfs_rename()
  2007-04-12  9:08 [AppArmor 00/41] AppArmor security module overview jjohansen
                   ` (19 preceding siblings ...)
  2007-04-12  9:08 ` [AppArmor 20/41] Pass struct vfsmount to the inode_unlink LSM hook jjohansen
@ 2007-04-12  9:08 ` jjohansen
  2007-04-12  9:08 ` [AppArmor 22/41] Pass struct vfsmount to the inode_rename LSM hook jjohansen
                   ` (22 subsequent siblings)
  43 siblings, 0 replies; 187+ messages in thread
From: jjohansen @ 2007-04-12  9:08 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, linux-fsdevel, chrisw, Tony Jones,
	Andreas Gruenbacher, John Johansen

[-- Attachment #1: vfs-rename.diff --]
[-- Type: text/plain, Size: 4708 bytes --]

The vfsmount will be passed down to the LSM hook so that LSMs can compute
pathnames.

Signed-off-by: Tony Jones <tonyj@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>

---
 fs/ecryptfs/inode.c |    7 ++++++-
 fs/namei.c          |   19 ++++++++++++-------
 fs/nfsd/vfs.c       |    3 ++-
 include/linux/fs.h  |    2 +-
 4 files changed, 21 insertions(+), 10 deletions(-)

--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c
@@ -598,19 +598,24 @@ ecryptfs_rename(struct inode *old_dir, s
 {
 	int rc;
 	struct dentry *lower_old_dentry;
+	struct vfsmount *lower_old_mnt;
 	struct dentry *lower_new_dentry;
+	struct vfsmount *lower_new_mnt;
 	struct dentry *lower_old_dir_dentry;
 	struct dentry *lower_new_dir_dentry;
 
 	lower_old_dentry = ecryptfs_dentry_to_lower(old_dentry);
+	lower_old_mnt = ecryptfs_dentry_to_lower_mnt(old_dentry);
 	lower_new_dentry = ecryptfs_dentry_to_lower(new_dentry);
+	lower_new_mnt = ecryptfs_dentry_to_lower_mnt(new_dentry);
 	dget(lower_old_dentry);
 	dget(lower_new_dentry);
 	lower_old_dir_dentry = dget_parent(lower_old_dentry);
 	lower_new_dir_dentry = dget_parent(lower_new_dentry);
 	lock_rename(lower_old_dir_dentry, lower_new_dir_dentry);
 	rc = vfs_rename(lower_old_dir_dentry->d_inode, lower_old_dentry,
-			lower_new_dir_dentry->d_inode, lower_new_dentry);
+			lower_old_mnt, lower_new_dir_dentry->d_inode,
+			lower_new_dentry, lower_new_mnt);
 	if (rc)
 		goto out_lock;
 	fsstack_copy_attr_all(new_dir, lower_new_dir_dentry->d_inode, NULL);
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2383,7 +2383,8 @@ asmlinkage long sys_link(const char __us
  *	   locking].
  */
 static int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,
-			  struct inode *new_dir, struct dentry *new_dentry)
+			  struct vfsmount *old_mnt, struct inode *new_dir,
+			  struct dentry *new_dentry, struct vfsmount *new_mnt)
 {
 	int error = 0;
 	struct inode *target;
@@ -2426,7 +2427,8 @@ static int vfs_rename_dir(struct inode *
 }
 
 static int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry,
-			    struct inode *new_dir, struct dentry *new_dentry)
+			    struct vfsmount *old_mnt, struct inode *new_dir,
+			    struct dentry *new_dentry, struct vfsmount *new_mnt)
 {
 	struct inode *target;
 	int error;
@@ -2454,7 +2456,8 @@ static int vfs_rename_other(struct inode
 }
 
 int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
-	       struct inode *new_dir, struct dentry *new_dentry)
+	        struct vfsmount *old_mnt, struct inode *new_dir,
+	        struct dentry *new_dentry, struct vfsmount *new_mnt)
 {
 	int error;
 	int is_dir = S_ISDIR(old_dentry->d_inode->i_mode);
@@ -2483,9 +2486,11 @@ int vfs_rename(struct inode *old_dir, st
 	old_name = fsnotify_oldname_init(old_dentry->d_name.name);
 
 	if (is_dir)
-		error = vfs_rename_dir(old_dir,old_dentry,new_dir,new_dentry);
+		error = vfs_rename_dir(old_dir, old_dentry, old_mnt,
+				       new_dir, new_dentry, new_mnt);
 	else
-		error = vfs_rename_other(old_dir,old_dentry,new_dir,new_dentry);
+		error = vfs_rename_other(old_dir, old_dentry, old_mnt,
+					 new_dir, new_dentry, new_mnt);
 	if (!error) {
 		const char *new_name = old_dentry->d_name.name;
 		fsnotify_move(old_dir, new_dir, old_name, new_name, is_dir,
@@ -2557,8 +2562,8 @@ static int do_rename(int olddfd, const c
 	if (new_dentry == trap)
 		goto exit5;
 
-	error = vfs_rename(old_dir->d_inode, old_dentry,
-				   new_dir->d_inode, new_dentry);
+	error = vfs_rename(old_dir->d_inode, old_dentry, oldnd.mnt,
+			   new_dir->d_inode, new_dentry, newnd.mnt);
 exit5:
 	dput(new_dentry);
 exit4:
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -1628,7 +1628,8 @@ nfsd_rename(struct svc_rqst *rqstp, stru
 			host_err = -EPERM;
 	} else
 #endif
-	host_err = vfs_rename(fdir, odentry, tdir, ndentry);
+	host_err = vfs_rename(fdir, odentry, ffhp->fh_export->ex_mnt,
+			      tdir, ndentry, tfhp->fh_export->ex_mnt);
 	if (!host_err && EX_ISSYNC(tfhp->fh_export)) {
 		host_err = nfsd_sync_dir(tdentry);
 		if (!host_err)
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -986,7 +986,7 @@ extern int vfs_symlink(struct inode *, s
 extern int vfs_link(struct dentry *, struct vfsmount *, struct inode *, struct dentry *, struct vfsmount *);
 extern int vfs_rmdir(struct inode *, struct dentry *, struct vfsmount *);
 extern int vfs_unlink(struct inode *, struct dentry *, struct vfsmount *);
-extern int vfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *);
+extern int vfs_rename(struct inode *, struct dentry *, struct vfsmount *, struct inode *, struct dentry *, struct vfsmount *);
 
 /*
  * VFS dentry helper functions.

-- 

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

* [AppArmor 22/41] Pass struct vfsmount to the inode_rename LSM hook
  2007-04-12  9:08 [AppArmor 00/41] AppArmor security module overview jjohansen
                   ` (20 preceding siblings ...)
  2007-04-12  9:08 ` [AppArmor 21/41] Add struct vfsmount parameters to vfs_rename() jjohansen
@ 2007-04-12  9:08 ` jjohansen
  2007-04-12  9:08 ` [AppArmor 23/41] Add a struct vfsmount parameter to vfs_setxattr() jjohansen
                   ` (21 subsequent siblings)
  43 siblings, 0 replies; 187+ messages in thread
From: jjohansen @ 2007-04-12  9:08 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, linux-fsdevel, chrisw, Tony Jones,
	Andreas Gruenbacher, John Johansen

[-- Attachment #1: security-rename.diff --]
[-- Type: text/plain, Size: 4640 bytes --]

This is needed for computing pathnames in the AppArmor LSM.

Signed-off-by: Tony Jones <tonyj@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>

---
 fs/namei.c               |    6 ++++--
 include/linux/security.h |   18 +++++++++++++-----
 security/dummy.c         |    4 +++-
 security/selinux/hooks.c |    8 ++++++--
 4 files changed, 26 insertions(+), 10 deletions(-)

--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2399,7 +2399,8 @@ static int vfs_rename_dir(struct inode *
 			return error;
 	}
 
-	error = security_inode_rename(old_dir, old_dentry, new_dir, new_dentry);
+	error = security_inode_rename(old_dir, old_dentry, old_mnt,
+				      new_dir, new_dentry, new_mnt);
 	if (error)
 		return error;
 
@@ -2433,7 +2434,8 @@ static int vfs_rename_other(struct inode
 	struct inode *target;
 	int error;
 
-	error = security_inode_rename(old_dir, old_dentry, new_dir, new_dentry);
+	error = security_inode_rename(old_dir, old_dentry, old_mnt,
+				      new_dir, new_dentry, new_mnt);
 	if (error)
 		return error;
 
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -336,8 +336,10 @@ struct request_sock;
  *	Check for permission to rename a file or directory.
  *	@old_dir contains the inode structure for parent of the old link.
  *	@old_dentry contains the dentry structure of the old link.
+ *	@old_mnt is the vfsmount corresponding to @old_dentry (may be NULL).
  *	@new_dir contains the inode structure for parent of the new link.
  *	@new_dentry contains the dentry structure of the new link.
+ *	@new_mnt is the vfsmount corresponding to @new_dentry (may be NULL).
  *	Return 0 if permission is granted.
  * @inode_readlink:
  *	Check the permission to read the symbolic link.
@@ -1230,7 +1232,9 @@ struct security_operations {
 	int (*inode_mknod) (struct inode *dir, struct dentry *dentry,
 			    struct vfsmount *mnt, int mode, dev_t dev);
 	int (*inode_rename) (struct inode *old_dir, struct dentry *old_dentry,
-	                     struct inode *new_dir, struct dentry *new_dentry);
+			     struct vfsmount *old_mnt,
+	                     struct inode *new_dir, struct dentry *new_dentry,
+			     struct vfsmount *new_mnt);
 	int (*inode_readlink) (struct dentry *dentry, struct vfsmount *mnt);
 	int (*inode_follow_link) (struct dentry *dentry, struct nameidata *nd);
 	int (*inode_permission) (struct inode *inode, int mask, struct nameidata *nd);
@@ -1696,14 +1700,16 @@ static inline int security_inode_mknod (
 
 static inline int security_inode_rename (struct inode *old_dir,
 					 struct dentry *old_dentry,
+					 struct vfsmount *old_mnt,
 					 struct inode *new_dir,
-					 struct dentry *new_dentry)
+					 struct dentry *new_dentry,
+					 struct vfsmount *new_mnt)
 {
         if (unlikely (IS_PRIVATE (old_dentry->d_inode) ||
             (new_dentry->d_inode && IS_PRIVATE (new_dentry->d_inode))))
 		return 0;
-	return security_ops->inode_rename (old_dir, old_dentry,
-					   new_dir, new_dentry);
+	return security_ops->inode_rename (old_dir, old_dentry, old_mnt,
+					   new_dir, new_dentry, new_mnt);
 }
 
 static inline int security_inode_readlink (struct dentry *dentry,
@@ -2419,8 +2425,10 @@ static inline int security_inode_mknod (
 
 static inline int security_inode_rename (struct inode *old_dir,
 					 struct dentry *old_dentry,
+					 struct vfsmount *old_mnt,
 					 struct inode *new_dir,
-					 struct dentry *new_dentry)
+					 struct dentry *new_dentry,
+					 struct vfsmount *new_mnt)
 {
 	return 0;
 }
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -310,8 +310,10 @@ static int dummy_inode_mknod (struct ino
 
 static int dummy_inode_rename (struct inode *old_inode,
 			       struct dentry *old_dentry,
+			       struct vfsmount *old_mnt,
 			       struct inode *new_inode,
-			       struct dentry *new_dentry)
+			       struct dentry *new_dentry,
+			       struct vfsmount *new_mnt)
 {
 	return 0;
 }
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2240,8 +2240,12 @@ static int selinux_inode_mknod(struct in
 	return may_create(dir, dentry, inode_mode_to_security_class(mode));
 }
 
-static int selinux_inode_rename(struct inode *old_inode, struct dentry *old_dentry,
-                                struct inode *new_inode, struct dentry *new_dentry)
+static int selinux_inode_rename(struct inode *old_inode,
+				struct dentry *old_dentry,
+				struct vfsmount *old_mnt,
+                                struct inode *new_inode,
+				struct dentry *new_dentry,
+				struct vfsmount *new_mnt)
 {
 	return may_rename(old_inode, old_dentry, new_inode, new_dentry);
 }

-- 

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

* [AppArmor 23/41] Add a struct vfsmount parameter to vfs_setxattr()
  2007-04-12  9:08 [AppArmor 00/41] AppArmor security module overview jjohansen
                   ` (21 preceding siblings ...)
  2007-04-12  9:08 ` [AppArmor 22/41] Pass struct vfsmount to the inode_rename LSM hook jjohansen
@ 2007-04-12  9:08 ` jjohansen
  2007-04-12  9:08 ` [AppArmor 24/41] Pass struct vfsmount to the inode_setxattr LSM hook jjohansen
                   ` (20 subsequent siblings)
  43 siblings, 0 replies; 187+ messages in thread
From: jjohansen @ 2007-04-12  9:08 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, linux-fsdevel, chrisw, Tony Jones,
	Andreas Gruenbacher, John Johansen

[-- Attachment #1: vfs-setxattr.diff --]
[-- Type: text/plain, Size: 4721 bytes --]

The vfsmount will be passed down to the LSM hook so that LSMs can compute
pathnames.

Signed-off-by: Tony Jones <tonyj@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>

---
 fs/nfsd/vfs.c         |   16 +++++++++++-----
 fs/xattr.c            |   16 ++++++++--------
 include/linux/xattr.h |    3 ++-
 3 files changed, 21 insertions(+), 14 deletions(-)

--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -396,7 +396,8 @@ static ssize_t nfsd_getxattr(struct dent
 
 #if defined(CONFIG_NFSD_V4)
 static int
-set_nfsv4_acl_one(struct dentry *dentry, struct posix_acl *pacl, char *key)
+set_nfsv4_acl_one(struct dentry *dentry, struct vfsmount *mnt,
+		  struct posix_acl *pacl, char *key)
 {
 	int len;
 	size_t buflen;
@@ -415,7 +416,7 @@ set_nfsv4_acl_one(struct dentry *dentry,
 		goto out;
 	}
 
-	error = vfs_setxattr(dentry, key, buf, len, 0);
+	error = vfs_setxattr(dentry, mnt, key, buf, len, 0);
 out:
 	kfree(buf);
 	return error;
@@ -428,6 +429,7 @@ nfsd4_set_nfs4_acl(struct svc_rqst *rqst
 	__be32 error;
 	int host_error;
 	struct dentry *dentry;
+	struct vfsmount *mnt;
 	struct inode *inode;
 	struct posix_acl *pacl = NULL, *dpacl = NULL;
 	unsigned int flags = 0;
@@ -438,6 +440,7 @@ nfsd4_set_nfs4_acl(struct svc_rqst *rqst
 		goto out;
 
 	dentry = fhp->fh_dentry;
+	mnt = fhp->fh_export->ex_mnt;
 	inode = dentry->d_inode;
 	if (S_ISDIR(inode->i_mode))
 		flags = NFS4_ACL_DIR;
@@ -449,12 +452,14 @@ nfsd4_set_nfs4_acl(struct svc_rqst *rqst
 	} else if (host_error < 0)
 		goto out_nfserr;
 
-	host_error = set_nfsv4_acl_one(dentry, pacl, POSIX_ACL_XATTR_ACCESS);
+	host_error = set_nfsv4_acl_one(dentry, mnt, pacl,
+				       POSIX_ACL_XATTR_ACCESS);
 	if (host_error < 0)
 		goto out_nfserr;
 
 	if (S_ISDIR(inode->i_mode)) {
-		host_error = set_nfsv4_acl_one(dentry, dpacl, POSIX_ACL_XATTR_DEFAULT);
+		host_error = set_nfsv4_acl_one(dentry, mnt, dpacl,
+					       POSIX_ACL_XATTR_DEFAULT);
 		if (host_error < 0)
 			goto out_nfserr;
 	}
@@ -1978,7 +1983,8 @@ nfsd_set_posix_acl(struct svc_fh *fhp, i
 		size = 0;
 
 	if (size)
-		error = vfs_setxattr(fhp->fh_dentry, name, value, size, 0);
+		error = vfs_setxattr(fhp->fh_dentry, fhp->fh_export->ex_mnt,
+				     name, value, size,0);
 	else {
 		if (!S_ISDIR(inode->i_mode) && type == ACL_TYPE_DEFAULT)
 			error = 0;
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -70,8 +70,8 @@ xattr_permission(struct inode *inode, co
 }
 
 int
-vfs_setxattr(struct dentry *dentry, char *name, void *value,
-		size_t size, int flags)
+vfs_setxattr(struct dentry *dentry, struct vfsmount *mnt, char *name,
+	     void *value, size_t size, int flags)
 {
 	struct inode *inode = dentry->d_inode;
 	int error;
@@ -194,8 +194,8 @@ EXPORT_SYMBOL_GPL(vfs_removexattr);
  * Extended attribute SET operations
  */
 static long
-setxattr(struct dentry *d, char __user *name, void __user *value,
-	 size_t size, int flags)
+setxattr(struct dentry *dentry, struct vfsmount *mnt, char __user *name,
+	 void __user *value, size_t size, int flags)
 {
 	int error;
 	void *kvalue = NULL;
@@ -222,7 +222,7 @@ setxattr(struct dentry *d, char __user *
 		}
 	}
 
-	error = vfs_setxattr(d, kname, kvalue, size, flags);
+	error = vfs_setxattr(dentry, mnt, kname, kvalue, size, flags);
 	kfree(kvalue);
 	return error;
 }
@@ -237,7 +237,7 @@ sys_setxattr(char __user *path, char __u
 	error = user_path_walk(path, &nd);
 	if (error)
 		return error;
-	error = setxattr(nd.dentry, name, value, size, flags);
+	error = setxattr(nd.dentry, nd.mnt, name, value, size, flags);
 	path_release(&nd);
 	return error;
 }
@@ -252,7 +252,7 @@ sys_lsetxattr(char __user *path, char __
 	error = user_path_walk_link(path, &nd);
 	if (error)
 		return error;
-	error = setxattr(nd.dentry, name, value, size, flags);
+	error = setxattr(nd.dentry, nd.mnt, name, value, size, flags);
 	path_release(&nd);
 	return error;
 }
@@ -270,7 +270,7 @@ sys_fsetxattr(int fd, char __user *name,
 		return error;
 	dentry = f->f_path.dentry;
 	audit_inode(NULL, dentry->d_inode);
-	error = setxattr(dentry, name, value, size, flags);
+	error = setxattr(dentry, f->f_vfsmnt, name, value, size, flags);
 	fput(f);
 	return error;
 }
--- a/include/linux/xattr.h
+++ b/include/linux/xattr.h
@@ -48,7 +48,8 @@ struct xattr_handler {
 
 ssize_t vfs_getxattr(struct dentry *, char *, void *, size_t);
 ssize_t vfs_listxattr(struct dentry *d, char *list, size_t size);
-int vfs_setxattr(struct dentry *, char *, void *, size_t, int);
+int vfs_setxattr(struct dentry *, struct vfsmount *, char *, void *, size_t,
+		 int);
 int vfs_removexattr(struct dentry *, char *);
 
 ssize_t generic_getxattr(struct dentry *dentry, const char *name, void *buffer, size_t size);

-- 

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

* [AppArmor 24/41] Pass struct vfsmount to the inode_setxattr LSM hook
  2007-04-12  9:08 [AppArmor 00/41] AppArmor security module overview jjohansen
                   ` (22 preceding siblings ...)
  2007-04-12  9:08 ` [AppArmor 23/41] Add a struct vfsmount parameter to vfs_setxattr() jjohansen
@ 2007-04-12  9:08 ` jjohansen
  2007-04-12  9:08 ` [AppArmor 25/41] Add a struct vfsmount parameter to vfs_getxattr() jjohansen
                   ` (19 subsequent siblings)
  43 siblings, 0 replies; 187+ messages in thread
From: jjohansen @ 2007-04-12  9:08 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, linux-fsdevel, chrisw, Tony Jones,
	Andreas Gruenbacher, John Johansen

[-- Attachment #1: security-setxattr.diff --]
[-- Type: text/plain, Size: 7658 bytes --]

This is needed for computing pathnames in the AppArmor LSM.

Signed-off-by: Tony Jones <tonyj@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>

---
 fs/xattr.c               |    4 ++--
 include/linux/security.h |   40 +++++++++++++++++++++++++---------------
 security/commoncap.c     |    4 ++--
 security/dummy.c         |    9 ++++++---
 security/selinux/hooks.c |    8 ++++++--
 5 files changed, 41 insertions(+), 24 deletions(-)

--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -81,7 +81,7 @@ vfs_setxattr(struct dentry *dentry, stru
 		return error;
 
 	mutex_lock(&inode->i_mutex);
-	error = security_inode_setxattr(dentry, name, value, size, flags);
+	error = security_inode_setxattr(dentry, mnt, name, value, size, flags);
 	if (error)
 		goto out;
 	error = -EOPNOTSUPP;
@@ -89,7 +89,7 @@ vfs_setxattr(struct dentry *dentry, stru
 		error = inode->i_op->setxattr(dentry, name, value, size, flags);
 		if (!error) {
 			fsnotify_xattr(dentry);
-			security_inode_post_setxattr(dentry, name, value,
+			security_inode_post_setxattr(dentry, mnt, name, value,
 						     size, flags);
 		}
 	} else if (!strncmp(name, XATTR_SECURITY_PREFIX,
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -49,7 +49,7 @@ extern void cap_capset_set (struct task_
 extern int cap_bprm_set_security (struct linux_binprm *bprm);
 extern void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe);
 extern int cap_bprm_secureexec(struct linux_binprm *bprm);
-extern int cap_inode_setxattr(struct dentry *dentry, char *name, void *value, size_t size, int flags);
+extern int cap_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt, char *name, void *value, size_t size, int flags);
 extern int cap_inode_removexattr(struct dentry *dentry, char *name);
 extern int cap_task_post_setuid (uid_t old_ruid, uid_t old_euid, uid_t old_suid, int flags);
 extern void cap_task_reparent_to_init (struct task_struct *p);
@@ -384,11 +384,11 @@ struct request_sock;
  *	inode.
  * @inode_setxattr:
  * 	Check permission before setting the extended attributes
- * 	@value identified by @name for @dentry.
+ * 	@value identified by @name for @dentry and @mnt.
  * 	Return 0 if permission is granted.
  * @inode_post_setxattr:
  * 	Update inode security field after successful setxattr operation.
- * 	@value identified by @name for @dentry.
+ * 	@value identified by @name for @dentry and @mnt.
  * @inode_getxattr:
  * 	Check permission before obtaining the extended attributes
  * 	identified by @name for @dentry.
@@ -1242,9 +1242,11 @@ struct security_operations {
 			      struct iattr *attr);
 	int (*inode_getattr) (struct vfsmount *mnt, struct dentry *dentry);
         void (*inode_delete) (struct inode *inode);
-	int (*inode_setxattr) (struct dentry *dentry, char *name, void *value,
-			       size_t size, int flags);
-	void (*inode_post_setxattr) (struct dentry *dentry, char *name, void *value,
+	int (*inode_setxattr) (struct dentry *dentry, struct vfsmount *mnt,
+			       char *name, void *value, size_t size, int flags);
+	void (*inode_post_setxattr) (struct dentry *dentry,
+				     struct vfsmount *mnt,
+				     char *name, void *value,
 				     size_t size, int flags);
 	int (*inode_getxattr) (struct dentry *dentry, char *name);
 	int (*inode_listxattr) (struct dentry *dentry);
@@ -1760,20 +1762,24 @@ static inline void security_inode_delete
 	security_ops->inode_delete (inode);
 }
 
-static inline int security_inode_setxattr (struct dentry *dentry, char *name,
+static inline int security_inode_setxattr (struct dentry *dentry,
+					   struct vfsmount *mnt, char *name,
 					   void *value, size_t size, int flags)
 {
 	if (unlikely (IS_PRIVATE (dentry->d_inode)))
 		return 0;
-	return security_ops->inode_setxattr (dentry, name, value, size, flags);
+	return security_ops->inode_setxattr (dentry, mnt, name, value, size,
+					     flags);
 }
 
-static inline void security_inode_post_setxattr (struct dentry *dentry, char *name,
-						void *value, size_t size, int flags)
+static inline void security_inode_post_setxattr (struct dentry *dentry,
+						 struct vfsmount *mnt,
+						 char *name, void *value,
+						 size_t size, int flags)
 {
 	if (unlikely (IS_PRIVATE (dentry->d_inode)))
 		return;
-	security_ops->inode_post_setxattr (dentry, name, value, size, flags);
+	security_ops->inode_post_setxattr (dentry, mnt, name, value, size, flags);
 }
 
 static inline int security_inode_getxattr (struct dentry *dentry, char *name)
@@ -2467,14 +2473,18 @@ static inline int security_inode_getattr
 static inline void security_inode_delete (struct inode *inode)
 { }
 
-static inline int security_inode_setxattr (struct dentry *dentry, char *name,
+static inline int security_inode_setxattr (struct dentry *dentry,
+					   struct vfsmount *mnt, char *name,
 					   void *value, size_t size, int flags)
 {
-	return cap_inode_setxattr(dentry, name, value, size, flags);
+	return cap_inode_setxattr(dentry, mnt, name, value, size, flags);
 }
 
-static inline void security_inode_post_setxattr (struct dentry *dentry, char *name,
-						 void *value, size_t size, int flags)
+static inline void security_inode_post_setxattr (struct dentry *dentry,
+						 struct vfsmount *mnt,
+						 char *name,
+						 void *value, size_t size,
+						 int flags)
 { }
 
 static inline int security_inode_getxattr (struct dentry *dentry, char *name)
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -191,8 +191,8 @@ int cap_bprm_secureexec (struct linux_bi
 		current->egid != current->gid);
 }
 
-int cap_inode_setxattr(struct dentry *dentry, char *name, void *value,
-		       size_t size, int flags)
+int cap_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt, char *name,
+		       void *value, size_t size, int flags)
 {
 	if (!strncmp(name, XATTR_SECURITY_PREFIX,
 		     sizeof(XATTR_SECURITY_PREFIX) - 1)  &&
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -350,8 +350,9 @@ static void dummy_inode_delete (struct i
 	return;
 }
 
-static int dummy_inode_setxattr (struct dentry *dentry, char *name, void *value,
-				size_t size, int flags)
+static int dummy_inode_setxattr (struct dentry *dentry, struct vfsmount *mnt,
+				 char *name, void *value, size_t size,
+				 int flags)
 {
 	if (!strncmp(name, XATTR_SECURITY_PREFIX,
 		     sizeof(XATTR_SECURITY_PREFIX) - 1) &&
@@ -360,7 +361,9 @@ static int dummy_inode_setxattr (struct 
 	return 0;
 }
 
-static void dummy_inode_post_setxattr (struct dentry *dentry, char *name, void *value,
+static void dummy_inode_post_setxattr (struct dentry *dentry,
+				       struct vfsmount *mnt,
+				       char *name, void *value,
 				       size_t size, int flags)
 {
 }
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2307,7 +2307,9 @@ static int selinux_inode_getattr(struct 
 	return dentry_has_perm(current, mnt, dentry, FILE__GETATTR);
 }
 
-static int selinux_inode_setxattr(struct dentry *dentry, char *name, void *value, size_t size, int flags)
+static int selinux_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt,
+				  char *name, void *value, size_t size,
+				  int flags)
 {
 	struct task_security_struct *tsec = current->security;
 	struct inode *inode = dentry->d_inode;
@@ -2367,7 +2369,9 @@ static int selinux_inode_setxattr(struct
 			    &ad);
 }
 
-static void selinux_inode_post_setxattr(struct dentry *dentry, char *name,
+static void selinux_inode_post_setxattr(struct dentry *dentry,
+					struct vfsmount *mnt,
+					char *name,
                                         void *value, size_t size, int flags)
 {
 	struct inode *inode = dentry->d_inode;

-- 

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

* [AppArmor 25/41] Add a struct vfsmount parameter to vfs_getxattr()
  2007-04-12  9:08 [AppArmor 00/41] AppArmor security module overview jjohansen
                   ` (23 preceding siblings ...)
  2007-04-12  9:08 ` [AppArmor 24/41] Pass struct vfsmount to the inode_setxattr LSM hook jjohansen
@ 2007-04-12  9:08 ` jjohansen
  2007-04-12  9:08 ` [AppArmor 26/41] Pass struct vfsmount to the inode_getxattr LSM hook jjohansen
                   ` (18 subsequent siblings)
  43 siblings, 0 replies; 187+ messages in thread
From: jjohansen @ 2007-04-12  9:08 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, linux-fsdevel, chrisw, Tony Jones,
	Andreas Gruenbacher, John Johansen

[-- Attachment #1: vfs-getxattr.diff --]
[-- Type: text/plain, Size: 6195 bytes --]

The vfsmount will be passed down to the LSM hook so that LSMs can compute
pathnames.

Signed-off-by: Tony Jones <tonyj@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>

---
 fs/nfsd/nfs4xdr.c         |    2 +-
 fs/nfsd/vfs.c             |   21 ++++++++++++---------
 fs/xattr.c                |   14 ++++++++------
 include/linux/nfsd/nfsd.h |    3 ++-
 include/linux/xattr.h     |    3 ++-
 5 files changed, 25 insertions(+), 18 deletions(-)

--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -1470,7 +1470,7 @@ nfsd4_encode_fattr(struct svc_fh *fhp, s
 	}
 	if (bmval0 & (FATTR4_WORD0_ACL | FATTR4_WORD0_ACLSUPPORT
 			| FATTR4_WORD0_SUPPORTED_ATTRS)) {
-		err = nfsd4_get_nfs4_acl(rqstp, dentry, &acl);
+		err = nfsd4_get_nfs4_acl(rqstp, dentry, exp->ex_mnt, &acl);
 		aclsupport = (err == 0);
 		if (bmval0 & FATTR4_WORD0_ACL) {
 			if (err == -EOPNOTSUPP)
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -378,11 +378,12 @@ out_nfserr:
 #if defined(CONFIG_NFSD_V2_ACL) || \
     defined(CONFIG_NFSD_V3_ACL) || \
     defined(CONFIG_NFSD_V4)
-static ssize_t nfsd_getxattr(struct dentry *dentry, char *key, void **buf)
+static ssize_t nfsd_getxattr(struct dentry *dentry, struct vfsmount *mnt,
+			     char *key, void **buf)
 {
 	ssize_t buflen;
 
-	buflen = vfs_getxattr(dentry, key, NULL, 0);
+	buflen = vfs_getxattr(dentry, mnt, key, NULL, 0);
 	if (buflen <= 0)
 		return buflen;
 
@@ -390,7 +391,7 @@ static ssize_t nfsd_getxattr(struct dent
 	if (!*buf)
 		return -ENOMEM;
 
-	return vfs_getxattr(dentry, key, *buf, buflen);
+	return vfs_getxattr(dentry, mnt, key, *buf, buflen);
 }
 #endif
 
@@ -479,13 +480,13 @@ out_nfserr:
 }
 
 static struct posix_acl *
-_get_posix_acl(struct dentry *dentry, char *key)
+_get_posix_acl(struct dentry *dentry, struct vfsmount *mnt, char *key)
 {
 	void *buf = NULL;
 	struct posix_acl *pacl = NULL;
 	int buflen;
 
-	buflen = nfsd_getxattr(dentry, key, &buf);
+	buflen = nfsd_getxattr(dentry, mnt, key, &buf);
 	if (!buflen)
 		buflen = -ENODATA;
 	if (buflen <= 0)
@@ -497,14 +498,15 @@ _get_posix_acl(struct dentry *dentry, ch
 }
 
 int
-nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry, struct nfs4_acl **acl)
+nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry,
+		   struct vfsmount *mnt, struct nfs4_acl **acl)
 {
 	struct inode *inode = dentry->d_inode;
 	int error = 0;
 	struct posix_acl *pacl = NULL, *dpacl = NULL;
 	unsigned int flags = 0;
 
-	pacl = _get_posix_acl(dentry, POSIX_ACL_XATTR_ACCESS);
+	pacl = _get_posix_acl(dentry, mnt, POSIX_ACL_XATTR_ACCESS);
 	if (IS_ERR(pacl) && PTR_ERR(pacl) == -ENODATA)
 		pacl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
 	if (IS_ERR(pacl)) {
@@ -514,7 +516,7 @@ nfsd4_get_nfs4_acl(struct svc_rqst *rqst
 	}
 
 	if (S_ISDIR(inode->i_mode)) {
-		dpacl = _get_posix_acl(dentry, POSIX_ACL_XATTR_DEFAULT);
+		dpacl = _get_posix_acl(dentry, mnt, POSIX_ACL_XATTR_DEFAULT);
 		if (IS_ERR(dpacl) && PTR_ERR(dpacl) == -ENODATA)
 			dpacl = NULL;
 		else if (IS_ERR(dpacl)) {
@@ -1938,7 +1940,8 @@ nfsd_get_posix_acl(struct svc_fh *fhp, i
 		return ERR_PTR(-EOPNOTSUPP);
 	}
 
-	size = nfsd_getxattr(fhp->fh_dentry, name, &value);
+	size = nfsd_getxattr(fhp->fh_dentry, fhp->fh_export->ex_mnt, name,
+			     &value);
 	if (size < 0)
 		return ERR_PTR(size);
 
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -107,7 +107,8 @@ out:
 EXPORT_SYMBOL_GPL(vfs_setxattr);
 
 ssize_t
-vfs_getxattr(struct dentry *dentry, char *name, void *value, size_t size)
+vfs_getxattr(struct dentry *dentry, struct vfsmount *mnt, char *name,
+	     void *value, size_t size)
 {
 	struct inode *inode = dentry->d_inode;
 	int error;
@@ -279,7 +280,8 @@ sys_fsetxattr(int fd, char __user *name,
  * Extended attribute GET operations
  */
 static ssize_t
-getxattr(struct dentry *d, char __user *name, void __user *value, size_t size)
+getxattr(struct dentry *dentry, struct vfsmount *mnt, char __user *name,
+	 void __user *value, size_t size)
 {
 	ssize_t error;
 	void *kvalue = NULL;
@@ -299,7 +301,7 @@ getxattr(struct dentry *d, char __user *
 			return -ENOMEM;
 	}
 
-	error = vfs_getxattr(d, kname, kvalue, size);
+	error = vfs_getxattr(dentry, mnt, kname, kvalue, size);
 	if (error > 0) {
 		if (size && copy_to_user(value, kvalue, error))
 			error = -EFAULT;
@@ -322,7 +324,7 @@ sys_getxattr(char __user *path, char __u
 	error = user_path_walk(path, &nd);
 	if (error)
 		return error;
-	error = getxattr(nd.dentry, name, value, size);
+	error = getxattr(nd.dentry, nd.mnt, name, value, size);
 	path_release(&nd);
 	return error;
 }
@@ -337,7 +339,7 @@ sys_lgetxattr(char __user *path, char __
 	error = user_path_walk_link(path, &nd);
 	if (error)
 		return error;
-	error = getxattr(nd.dentry, name, value, size);
+	error = getxattr(nd.dentry, nd.mnt, name, value, size);
 	path_release(&nd);
 	return error;
 }
@@ -351,7 +353,7 @@ sys_fgetxattr(int fd, char __user *name,
 	f = fget(fd);
 	if (!f)
 		return error;
-	error = getxattr(f->f_path.dentry, name, value, size);
+	error = getxattr(f->f_path.dentry, f->f_path.mnt, name, value, size);
 	fput(f);
 	return error;
 }
--- a/include/linux/nfsd/nfsd.h
+++ b/include/linux/nfsd/nfsd.h
@@ -77,7 +77,8 @@ __be32		nfsd_setattr(struct svc_rqst *, 
 #ifdef CONFIG_NFSD_V4
 __be32          nfsd4_set_nfs4_acl(struct svc_rqst *, struct svc_fh *,
                     struct nfs4_acl *);
-int             nfsd4_get_nfs4_acl(struct svc_rqst *, struct dentry *, struct nfs4_acl **);
+int             nfsd4_get_nfs4_acl(struct svc_rqst *, struct dentry *,
+				struct vfsmount *mnt, struct nfs4_acl **);
 #endif /* CONFIG_NFSD_V4 */
 __be32		nfsd_create(struct svc_rqst *, struct svc_fh *,
 				char *name, int len, struct iattr *attrs,
--- a/include/linux/xattr.h
+++ b/include/linux/xattr.h
@@ -46,7 +46,8 @@ struct xattr_handler {
 		   size_t size, int flags);
 };
 
-ssize_t vfs_getxattr(struct dentry *, char *, void *, size_t);
+ssize_t vfs_getxattr(struct dentry *, struct vfsmount *, char *, void *,
+		     size_t);
 ssize_t vfs_listxattr(struct dentry *d, char *list, size_t size);
 int vfs_setxattr(struct dentry *, struct vfsmount *, char *, void *, size_t,
 		 int);

-- 

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

* [AppArmor 26/41] Pass struct vfsmount to the inode_getxattr LSM hook
  2007-04-12  9:08 [AppArmor 00/41] AppArmor security module overview jjohansen
                   ` (24 preceding siblings ...)
  2007-04-12  9:08 ` [AppArmor 25/41] Add a struct vfsmount parameter to vfs_getxattr() jjohansen
@ 2007-04-12  9:08 ` jjohansen
  2007-04-12  9:08 ` [AppArmor 27/41] Add a struct vfsmount parameter to vfs_listxattr() jjohansen
                   ` (17 subsequent siblings)
  43 siblings, 0 replies; 187+ messages in thread
From: jjohansen @ 2007-04-12  9:08 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, linux-fsdevel, chrisw, Tony Jones,
	Andreas Gruenbacher, John Johansen

[-- Attachment #1: security-getxattr.diff --]
[-- Type: text/plain, Size: 3185 bytes --]

This is needed for computing pathnames in the AppArmor LSM.

Signed-off-by: Tony Jones <tonyj@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>

---
 fs/xattr.c               |    2 +-
 include/linux/security.h |   13 ++++++++-----
 security/dummy.c         |    3 ++-
 security/selinux/hooks.c |    3 ++-
 4 files changed, 13 insertions(+), 8 deletions(-)

--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -117,7 +117,7 @@ vfs_getxattr(struct dentry *dentry, stru
 	if (error)
 		return error;
 
-	error = security_inode_getxattr(dentry, name);
+	error = security_inode_getxattr(dentry, mnt, name);
 	if (error)
 		return error;
 
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -391,7 +391,7 @@ struct request_sock;
  * 	@value identified by @name for @dentry and @mnt.
  * @inode_getxattr:
  * 	Check permission before obtaining the extended attributes
- * 	identified by @name for @dentry.
+ * 	identified by @name for @dentry and @mnt.
  * 	Return 0 if permission is granted.
  * @inode_listxattr:
  * 	Check permission before obtaining the list of extended attribute 
@@ -1248,7 +1248,8 @@ struct security_operations {
 				     struct vfsmount *mnt,
 				     char *name, void *value,
 				     size_t size, int flags);
-	int (*inode_getxattr) (struct dentry *dentry, char *name);
+	int (*inode_getxattr) (struct dentry *dentry, struct vfsmount *mnt,
+			       char *name);
 	int (*inode_listxattr) (struct dentry *dentry);
 	int (*inode_removexattr) (struct dentry *dentry, char *name);
 	const char *(*inode_xattr_getsuffix) (void);
@@ -1782,11 +1783,12 @@ static inline void security_inode_post_s
 	security_ops->inode_post_setxattr (dentry, mnt, name, value, size, flags);
 }
 
-static inline int security_inode_getxattr (struct dentry *dentry, char *name)
+static inline int security_inode_getxattr (struct dentry *dentry,
+					    struct vfsmount *mnt, char *name)
 {
 	if (unlikely (IS_PRIVATE (dentry->d_inode)))
 		return 0;
-	return security_ops->inode_getxattr (dentry, name);
+	return security_ops->inode_getxattr (dentry, mnt, name);
 }
 
 static inline int security_inode_listxattr (struct dentry *dentry)
@@ -2487,7 +2489,8 @@ static inline void security_inode_post_s
 						 int flags)
 { }
 
-static inline int security_inode_getxattr (struct dentry *dentry, char *name)
+static inline int security_inode_getxattr (struct dentry *dentry,
+					    struct vfsmount *mnt, char *name)
 {
 	return 0;
 }
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -368,7 +368,8 @@ static void dummy_inode_post_setxattr (s
 {
 }
 
-static int dummy_inode_getxattr (struct dentry *dentry, char *name)
+static int dummy_inode_getxattr (struct dentry *dentry,
+			          struct vfsmount *mnt, char *name)
 {
 	return 0;
 }
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2395,7 +2395,8 @@ static void selinux_inode_post_setxattr(
 	return;
 }
 
-static int selinux_inode_getxattr (struct dentry *dentry, char *name)
+static int selinux_inode_getxattr (struct dentry *dentry, struct vfsmount *mnt,
+				   char *name)
 {
 	return dentry_has_perm(current, NULL, dentry, FILE__GETATTR);
 }

-- 

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

* [AppArmor 27/41] Add a struct vfsmount parameter to vfs_listxattr()
  2007-04-12  9:08 [AppArmor 00/41] AppArmor security module overview jjohansen
                   ` (25 preceding siblings ...)
  2007-04-12  9:08 ` [AppArmor 26/41] Pass struct vfsmount to the inode_getxattr LSM hook jjohansen
@ 2007-04-12  9:08 ` jjohansen
  2007-04-12  9:08 ` [AppArmor 28/41] Pass struct vfsmount to the inode_listxattr LSM hook jjohansen
                   ` (16 subsequent siblings)
  43 siblings, 0 replies; 187+ messages in thread
From: jjohansen @ 2007-04-12  9:08 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, linux-fsdevel, chrisw, Tony Jones,
	Andreas Gruenbacher, John Johansen

[-- Attachment #1: vfs-listxattr.diff --]
[-- Type: text/plain, Size: 3138 bytes --]

The vfsmount will be passed down to the LSM hook so that LSMs can compute
pathnames.

Signed-off-by: Tony Jones <tonyj@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>

---
 fs/xattr.c            |   25 ++++++++++++++-----------
 include/linux/xattr.h |    3 ++-
 2 files changed, 16 insertions(+), 12 deletions(-)

--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -144,18 +144,20 @@ vfs_getxattr(struct dentry *dentry, stru
 EXPORT_SYMBOL_GPL(vfs_getxattr);
 
 ssize_t
-vfs_listxattr(struct dentry *d, char *list, size_t size)
+vfs_listxattr(struct dentry *dentry, struct vfsmount *mnt, char *list,
+	      size_t size)
 {
+	struct inode *inode = dentry->d_inode;
 	ssize_t error;
 
-	error = security_inode_listxattr(d);
+	error = security_inode_listxattr(dentry);
 	if (error)
 		return error;
 	error = -EOPNOTSUPP;
-	if (d->d_inode->i_op && d->d_inode->i_op->listxattr) {
-		error = d->d_inode->i_op->listxattr(d, list, size);
-	} else {
-		error = security_inode_listsecurity(d->d_inode, list, size);
+	if (inode->i_op && inode->i_op->listxattr)
+		error = inode->i_op->listxattr(dentry, list, size);
+	else {
+		error = security_inode_listsecurity(inode, list, size);
 		if (size && error > size)
 			error = -ERANGE;
 	}
@@ -362,7 +364,8 @@ sys_fgetxattr(int fd, char __user *name,
  * Extended attribute LIST operations
  */
 static ssize_t
-listxattr(struct dentry *d, char __user *list, size_t size)
+listxattr(struct dentry *dentry, struct vfsmount *mnt, char __user *list,
+	  size_t size)
 {
 	ssize_t error;
 	char *klist = NULL;
@@ -375,7 +378,7 @@ listxattr(struct dentry *d, char __user 
 			return -ENOMEM;
 	}
 
-	error = vfs_listxattr(d, klist, size);
+	error = vfs_listxattr(dentry, mnt, klist, size);
 	if (error > 0) {
 		if (size && copy_to_user(list, klist, error))
 			error = -EFAULT;
@@ -397,7 +400,7 @@ sys_listxattr(char __user *path, char __
 	error = user_path_walk(path, &nd);
 	if (error)
 		return error;
-	error = listxattr(nd.dentry, list, size);
+	error = listxattr(nd.dentry, nd.mnt, list, size);
 	path_release(&nd);
 	return error;
 }
@@ -411,7 +414,7 @@ sys_llistxattr(char __user *path, char _
 	error = user_path_walk_link(path, &nd);
 	if (error)
 		return error;
-	error = listxattr(nd.dentry, list, size);
+	error = listxattr(nd.dentry, nd.mnt, list, size);
 	path_release(&nd);
 	return error;
 }
@@ -425,7 +428,7 @@ sys_flistxattr(int fd, char __user *list
 	f = fget(fd);
 	if (!f)
 		return error;
-	error = listxattr(f->f_path.dentry, list, size);
+	error = listxattr(f->f_path.dentry, f->f_path.mnt, list, size);
 	fput(f);
 	return error;
 }
--- a/include/linux/xattr.h
+++ b/include/linux/xattr.h
@@ -48,7 +48,8 @@ struct xattr_handler {
 
 ssize_t vfs_getxattr(struct dentry *, struct vfsmount *, char *, void *,
 		     size_t);
-ssize_t vfs_listxattr(struct dentry *d, char *list, size_t size);
+ssize_t vfs_listxattr(struct dentry *d, struct vfsmount *, char *list,
+		      size_t size);
 int vfs_setxattr(struct dentry *, struct vfsmount *, char *, void *, size_t,
 		 int);
 int vfs_removexattr(struct dentry *, char *);

-- 

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

* [AppArmor 28/41] Pass struct vfsmount to the inode_listxattr LSM hook
  2007-04-12  9:08 [AppArmor 00/41] AppArmor security module overview jjohansen
                   ` (26 preceding siblings ...)
  2007-04-12  9:08 ` [AppArmor 27/41] Add a struct vfsmount parameter to vfs_listxattr() jjohansen
@ 2007-04-12  9:08 ` jjohansen
  2007-04-12  9:08 ` [AppArmor 29/41] Add a struct vfsmount parameter to vfs_removexattr() jjohansen
                   ` (15 subsequent siblings)
  43 siblings, 0 replies; 187+ messages in thread
From: jjohansen @ 2007-04-12  9:08 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, linux-fsdevel, chrisw, Tony Jones,
	Andreas Gruenbacher, John Johansen

[-- Attachment #1: security-listxattr.diff --]
[-- Type: text/plain, Size: 3165 bytes --]

This is needed for computing pathnames in the AppArmor LSM.

Signed-off-by: Tony Jones <tonyj@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>

---
 fs/xattr.c               |    2 +-
 include/linux/security.h |   12 +++++++-----
 security/dummy.c         |    2 +-
 security/selinux/hooks.c |    2 +-
 4 files changed, 10 insertions(+), 8 deletions(-)

--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -150,7 +150,7 @@ vfs_listxattr(struct dentry *dentry, str
 	struct inode *inode = dentry->d_inode;
 	ssize_t error;
 
-	error = security_inode_listxattr(dentry);
+	error = security_inode_listxattr(dentry, mnt);
 	if (error)
 		return error;
 	error = -EOPNOTSUPP;
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -395,7 +395,7 @@ struct request_sock;
  * 	Return 0 if permission is granted.
  * @inode_listxattr:
  * 	Check permission before obtaining the list of extended attribute 
- * 	names for @dentry.
+ * 	names for @dentry and @mnt.
  * 	Return 0 if permission is granted.
  * @inode_removexattr:
  * 	Check permission before removing the extended attribute
@@ -1250,7 +1250,7 @@ struct security_operations {
 				     size_t size, int flags);
 	int (*inode_getxattr) (struct dentry *dentry, struct vfsmount *mnt,
 			       char *name);
-	int (*inode_listxattr) (struct dentry *dentry);
+	int (*inode_listxattr) (struct dentry *dentry, struct vfsmount *mnt);
 	int (*inode_removexattr) (struct dentry *dentry, char *name);
 	const char *(*inode_xattr_getsuffix) (void);
   	int (*inode_getsecurity)(const struct inode *inode, const char *name, void *buffer, size_t size, int err);
@@ -1791,11 +1791,12 @@ static inline int security_inode_getxatt
 	return security_ops->inode_getxattr (dentry, mnt, name);
 }
 
-static inline int security_inode_listxattr (struct dentry *dentry)
+static inline int security_inode_listxattr (struct dentry *dentry,
+					    struct vfsmount *mnt)
 {
 	if (unlikely (IS_PRIVATE (dentry->d_inode)))
 		return 0;
-	return security_ops->inode_listxattr (dentry);
+	return security_ops->inode_listxattr (dentry, mnt);
 }
 
 static inline int security_inode_removexattr (struct dentry *dentry, char *name)
@@ -2495,7 +2496,8 @@ static inline int security_inode_getxatt
 	return 0;
 }
 
-static inline int security_inode_listxattr (struct dentry *dentry)
+static inline int security_inode_listxattr (struct dentry *dentry,
+					    struct vfsmount *mnt)
 {
 	return 0;
 }
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -374,7 +374,7 @@ static int dummy_inode_getxattr (struct 
 	return 0;
 }
 
-static int dummy_inode_listxattr (struct dentry *dentry)
+static int dummy_inode_listxattr (struct dentry *dentry, struct vfsmount *mnt)
 {
 	return 0;
 }
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2401,7 +2401,7 @@ static int selinux_inode_getxattr (struc
 	return dentry_has_perm(current, NULL, dentry, FILE__GETATTR);
 }
 
-static int selinux_inode_listxattr (struct dentry *dentry)
+static int selinux_inode_listxattr (struct dentry *dentry, struct vfsmount *mnt)
 {
 	return dentry_has_perm(current, NULL, dentry, FILE__GETATTR);
 }

-- 

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

* [AppArmor 29/41] Add a struct vfsmount parameter to vfs_removexattr()
  2007-04-12  9:08 [AppArmor 00/41] AppArmor security module overview jjohansen
                   ` (27 preceding siblings ...)
  2007-04-12  9:08 ` [AppArmor 28/41] Pass struct vfsmount to the inode_listxattr LSM hook jjohansen
@ 2007-04-12  9:08 ` jjohansen
  2007-04-12  9:08 ` [AppArmor 30/41] Pass struct vfsmount to the inode_removexattr LSM hook jjohansen
                   ` (14 subsequent siblings)
  43 siblings, 0 replies; 187+ messages in thread
From: jjohansen @ 2007-04-12  9:08 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, linux-fsdevel, chrisw, Tony Jones,
	Andreas Gruenbacher, John Johansen

[-- Attachment #1: vfs-removexattr.diff --]
[-- Type: text/plain, Size: 2889 bytes --]

The vfsmount will be passed down to the LSM hook so that LSMs can compute
pathnames.

Signed-off-by: Tony Jones <tonyj@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>

---
 fs/nfsd/vfs.c         |    3 ++-
 fs/xattr.c            |   12 ++++++------
 include/linux/xattr.h |    2 +-
 3 files changed, 9 insertions(+), 8 deletions(-)

--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -1992,7 +1992,8 @@ nfsd_set_posix_acl(struct svc_fh *fhp, i
 		if (!S_ISDIR(inode->i_mode) && type == ACL_TYPE_DEFAULT)
 			error = 0;
 		else {
-			error = vfs_removexattr(fhp->fh_dentry, name);
+			error = vfs_removexattr(fhp->fh_dentry,
+						fhp->fh_export->ex_mnt, name);
 			if (error == -ENODATA)
 				error = 0;
 		}
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -166,7 +166,7 @@ vfs_listxattr(struct dentry *dentry, str
 EXPORT_SYMBOL_GPL(vfs_listxattr);
 
 int
-vfs_removexattr(struct dentry *dentry, char *name)
+vfs_removexattr(struct dentry *dentry, struct vfsmount *mnt, char *name)
 {
 	struct inode *inode = dentry->d_inode;
 	int error;
@@ -437,7 +437,7 @@ sys_flistxattr(int fd, char __user *list
  * Extended attribute REMOVE operations
  */
 static long
-removexattr(struct dentry *d, char __user *name)
+removexattr(struct dentry *dentry, struct vfsmount *mnt, char __user *name)
 {
 	int error;
 	char kname[XATTR_NAME_MAX + 1];
@@ -448,7 +448,7 @@ removexattr(struct dentry *d, char __use
 	if (error < 0)
 		return error;
 
-	return vfs_removexattr(d, kname);
+	return vfs_removexattr(dentry, mnt, kname);
 }
 
 asmlinkage long
@@ -460,7 +460,7 @@ sys_removexattr(char __user *path, char 
 	error = user_path_walk(path, &nd);
 	if (error)
 		return error;
-	error = removexattr(nd.dentry, name);
+	error = removexattr(nd.dentry, nd.mnt, name);
 	path_release(&nd);
 	return error;
 }
@@ -474,7 +474,7 @@ sys_lremovexattr(char __user *path, char
 	error = user_path_walk_link(path, &nd);
 	if (error)
 		return error;
-	error = removexattr(nd.dentry, name);
+	error = removexattr(nd.dentry, nd.mnt, name);
 	path_release(&nd);
 	return error;
 }
@@ -491,7 +491,7 @@ sys_fremovexattr(int fd, char __user *na
 		return error;
 	dentry = f->f_path.dentry;
 	audit_inode(NULL, dentry->d_inode);
-	error = removexattr(dentry, name);
+	error = removexattr(dentry, f->f_path.mnt, name);
 	fput(f);
 	return error;
 }
--- a/include/linux/xattr.h
+++ b/include/linux/xattr.h
@@ -52,7 +52,7 @@ ssize_t vfs_listxattr(struct dentry *d, 
 		      size_t size);
 int vfs_setxattr(struct dentry *, struct vfsmount *, char *, void *, size_t,
 		 int);
-int vfs_removexattr(struct dentry *, char *);
+int vfs_removexattr(struct dentry *, struct vfsmount *, char *);
 
 ssize_t generic_getxattr(struct dentry *dentry, const char *name, void *buffer, size_t size);
 ssize_t generic_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size);

-- 

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

* [AppArmor 30/41] Pass struct vfsmount to the inode_removexattr LSM hook
  2007-04-12  9:08 [AppArmor 00/41] AppArmor security module overview jjohansen
                   ` (28 preceding siblings ...)
  2007-04-12  9:08 ` [AppArmor 29/41] Add a struct vfsmount parameter to vfs_removexattr() jjohansen
@ 2007-04-12  9:08 ` jjohansen
  2007-04-12  9:08 ` [AppArmor 31/41] Fix __d_path() for lazy unmounts and make it unambiguous; exclude unreachable mount points from /proc/mounts jjohansen
                   ` (13 subsequent siblings)
  43 siblings, 0 replies; 187+ messages in thread
From: jjohansen @ 2007-04-12  9:08 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, linux-fsdevel, chrisw, Tony Jones,
	Andreas Gruenbacher, John Johansen

[-- Attachment #1: security-removexattr.diff --]
[-- Type: text/plain, Size: 4369 bytes --]

This is needed for computing pathnames in the AppArmor LSM.

Signed-off-by: Tony Jones <tonyj@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>

---
 fs/xattr.c               |    2 +-
 include/linux/security.h |   15 +++++++++------
 security/commoncap.c     |    3 ++-
 security/dummy.c         |    3 ++-
 security/selinux/hooks.c |    3 ++-
 5 files changed, 16 insertions(+), 10 deletions(-)

--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -178,7 +178,7 @@ vfs_removexattr(struct dentry *dentry, s
 	if (error)
 		return error;
 
-	error = security_inode_removexattr(dentry, name);
+	error = security_inode_removexattr(dentry, mnt, name);
 	if (error)
 		return error;
 
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -50,7 +50,7 @@ extern int cap_bprm_set_security (struct
 extern void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe);
 extern int cap_bprm_secureexec(struct linux_binprm *bprm);
 extern int cap_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt, char *name, void *value, size_t size, int flags);
-extern int cap_inode_removexattr(struct dentry *dentry, char *name);
+extern int cap_inode_removexattr(struct dentry *dentry, struct vfsmount *mnt, char *name);
 extern int cap_task_post_setuid (uid_t old_ruid, uid_t old_euid, uid_t old_suid, int flags);
 extern void cap_task_reparent_to_init (struct task_struct *p);
 extern int cap_syslog (int type);
@@ -1251,7 +1251,8 @@ struct security_operations {
 	int (*inode_getxattr) (struct dentry *dentry, struct vfsmount *mnt,
 			       char *name);
 	int (*inode_listxattr) (struct dentry *dentry, struct vfsmount *mnt);
-	int (*inode_removexattr) (struct dentry *dentry, char *name);
+	int (*inode_removexattr) (struct dentry *dentry, struct vfsmount *mnt,
+				  char *name);
 	const char *(*inode_xattr_getsuffix) (void);
   	int (*inode_getsecurity)(const struct inode *inode, const char *name, void *buffer, size_t size, int err);
   	int (*inode_setsecurity)(struct inode *inode, const char *name, const void *value, size_t size, int flags);
@@ -1799,11 +1800,12 @@ static inline int security_inode_listxat
 	return security_ops->inode_listxattr (dentry, mnt);
 }
 
-static inline int security_inode_removexattr (struct dentry *dentry, char *name)
+static inline int security_inode_removexattr (struct dentry *dentry,
+					      struct vfsmount *mnt, char *name)
 {
 	if (unlikely (IS_PRIVATE (dentry->d_inode)))
 		return 0;
-	return security_ops->inode_removexattr (dentry, name);
+	return security_ops->inode_removexattr (dentry, mnt, name);
 }
 
 static inline const char *security_inode_xattr_getsuffix(void)
@@ -2502,9 +2504,10 @@ static inline int security_inode_listxat
 	return 0;
 }
 
-static inline int security_inode_removexattr (struct dentry *dentry, char *name)
+static inline int security_inode_removexattr (struct dentry *dentry,
+					      struct vfsmount *mnt, char *name)
 {
-	return cap_inode_removexattr(dentry, name);
+	return cap_inode_removexattr(dentry, mnt, name);
 }
 
 static inline const char *security_inode_xattr_getsuffix (void)
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -201,7 +201,8 @@ int cap_inode_setxattr(struct dentry *de
 	return 0;
 }
 
-int cap_inode_removexattr(struct dentry *dentry, char *name)
+int cap_inode_removexattr(struct dentry *dentry, struct vfsmount *mnt,
+			  char *name)
 {
 	if (!strncmp(name, XATTR_SECURITY_PREFIX,
 		     sizeof(XATTR_SECURITY_PREFIX) - 1)  &&
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -379,7 +379,8 @@ static int dummy_inode_listxattr (struct
 	return 0;
 }
 
-static int dummy_inode_removexattr (struct dentry *dentry, char *name)
+static int dummy_inode_removexattr (struct dentry *dentry, struct vfsmount *mnt,
+				    char *name)
 {
 	if (!strncmp(name, XATTR_SECURITY_PREFIX,
 		     sizeof(XATTR_SECURITY_PREFIX) - 1) &&
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2406,7 +2406,8 @@ static int selinux_inode_listxattr (stru
 	return dentry_has_perm(current, NULL, dentry, FILE__GETATTR);
 }
 
-static int selinux_inode_removexattr (struct dentry *dentry, char *name)
+static int selinux_inode_removexattr (struct dentry *dentry,
+				      struct vfsmount *mnt, char *name)
 {
 	if (strcmp(name, XATTR_NAME_SELINUX)) {
 		if (!strncmp(name, XATTR_SECURITY_PREFIX,

-- 

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

* [AppArmor 31/41] Fix __d_path() for lazy unmounts and make it unambiguous; exclude unreachable mount points from /proc/mounts
  2007-04-12  9:08 [AppArmor 00/41] AppArmor security module overview jjohansen
                   ` (29 preceding siblings ...)
  2007-04-12  9:08 ` [AppArmor 30/41] Pass struct vfsmount to the inode_removexattr LSM hook jjohansen
@ 2007-04-12  9:08 ` jjohansen
  2007-04-12  9:58   ` Alan Cox
  2007-04-12  9:08 ` [AppArmor 32/41] Make d_path() consistent across mount operations jjohansen
                   ` (12 subsequent siblings)
  43 siblings, 1 reply; 187+ messages in thread
From: jjohansen @ 2007-04-12  9:08 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, linux-fsdevel, chrisw,
	Andreas Gruenbacher, Andrew Morton

[-- Attachment #1: fix-__d_path-for-lazy-unmounts-and-make-it-unambiguous.patch --]
[-- Type: text/plain, Size: 13130 bytes --]

First, when d_path() hits a lazily unmounted mount point, it tries to prepend
the name of the lazily unmounted dentry to the path name.  It gets this wrong,
and also overwrites the slash that separates the name from the following
pathname component.

Second, it isn't always possible to tell from the __d_path result whether the
specified root and rootmnt (i.e., the chroot) was reached: lazy unmounts of
bind mounts will produce a path that does start with a non-slash so we can
tell from that, but other lazy unmounts will produce a path that starts with a
slash, just like "ordinary" paths.

Third, sys_getcwd() shouldn't return disconnected paths.  The patch checks for
that, and makes it fail with -ENOENT in that case.

Fourth, this now allows us to tell unreachable mount points from reachable
ones when generating the /proc/mounts and /proc/$pid/mountstats files. 
Unreachable mount points are not interesting to processes (they can't get
there, anyway), so we hide unreachable mounts.  In particular, ordinary
processes also will no longer see the rootfs mount (it is unreachable, after
all).  The rootfs mount point will still be reachable to processes like the
initial initrd init process, and so those processes will continue to see this
mount point.

The attached patch cleans up __d_path() to fix the bug with overlapping
pathname components.  It also adds a @fail_deleted argument, which allows to
get rid of some of the mess in sys_getcwd().  We make sure that paths will
only start with a slash if the path leads all the way up to the root.  If the
resulting path would otherwise be empty, we return "." instead so that some
users of seq_path for files in /proc won't break.

The @fail_deleted argument allows sys_getcwd() to be simplified.  Grabbing the
dcache_lock can be moved into __d_path().

The @fail_deleted argument could be added to d_path() as well: this would
allow callers to recognize deleted files without having to resort to the
ambiguous check for the " (deleted)" string at the end of the pathnames.  This
is not currently done, but it might be worthwhile.

This patch also removes some code duplication between mounts_open() and
mountstats_open().

Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Reviewed-by: NeilBrown <neilb@suse.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

---
 fs/dcache.c    |  157 +++++++++++++++++++++++++++++++--------------------------
 fs/namespace.c |   23 +++++++-
 fs/proc/base.c |   52 +++++++-----------
 3 files changed, 131 insertions(+), 101 deletions(-)

--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1732,52 +1732,51 @@ shouldnt_be_hashed:
 }
 
 /**
- * d_path - return the path of a dentry
+ * __d_path - return the path of a dentry
  * @dentry: dentry to report
  * @vfsmnt: vfsmnt to which the dentry belongs
  * @root: root dentry
  * @rootmnt: vfsmnt to which the root dentry belongs
  * @buffer: buffer to return value in
  * @buflen: buffer length
+ * @fail_deleted: what to return for deleted files
  *
- * Convert a dentry into an ASCII path name. If the entry has been deleted
+ * Convert a dentry into an ASCII path name. If the entry has been deleted,
+ * then if @fail_deleted is true, ERR_PTR(-ENOENT) is returned. Otherwise,
  * the string " (deleted)" is appended. Note that this is ambiguous.
  *
- * Returns the buffer or an error code if the path was too long.
+ * If @dentry is not connected to @root, the path returned will be relative
+ * (i.e., it will not start with a slash).
  *
- * "buflen" should be positive. Caller holds the dcache_lock.
+ * Returns the buffer or an error code.
  */
-static char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt,
-			struct dentry *root, struct vfsmount *rootmnt,
-			char *buffer, int buflen)
-{
-	char * end = buffer+buflen;
-	char * retval;
-	int namelen;
+static char *__d_path(struct dentry *dentry, struct vfsmount *vfsmnt,
+		      struct dentry *root, struct vfsmount *rootmnt,
+		      char *buffer, int buflen, int fail_deleted)
+{
+	int namelen, is_slash;
+
+	if (buflen < 2)
+		return ERR_PTR(-ENAMETOOLONG);
+	buffer += --buflen;
+	*buffer = '\0';
 
-	*--end = '\0';
-	buflen--;
+	spin_lock(&dcache_lock);
 	if (!IS_ROOT(dentry) && d_unhashed(dentry)) {
-		buflen -= 10;
-		end -= 10;
-		if (buflen < 0)
+		if (fail_deleted) {
+			buffer = ERR_PTR(-ENOENT);
+			goto out;
+		}
+		if (buflen < 10)
 			goto Elong;
-		memcpy(end, " (deleted)", 10);
+		buflen -= 10;
+		buffer -= 10;
+		memcpy(buffer, " (deleted)", 10);
 	}
-
-	if (buflen < 1)
-		goto Elong;
-	/* Get '/' right */
-	retval = end-1;
-	*retval = '/';
-
-	for (;;) {
+	while (dentry != root || vfsmnt != rootmnt) {
 		struct dentry * parent;
 
-		if (dentry == root && vfsmnt == rootmnt)
-			break;
 		if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
-			/* Global root? */
 			spin_lock(&vfsmount_lock);
 			if (vfsmnt->mnt_parent == vfsmnt) {
 				spin_unlock(&vfsmount_lock);
@@ -1791,33 +1790,63 @@ static char * __d_path( struct dentry *d
 		parent = dentry->d_parent;
 		prefetch(parent);
 		namelen = dentry->d_name.len;
-		buflen -= namelen + 1;
-		if (buflen < 0)
+		if (buflen < namelen + 1)
 			goto Elong;
-		end -= namelen;
-		memcpy(end, dentry->d_name.name, namelen);
-		*--end = '/';
-		retval = end;
+		buflen -= namelen + 1;
+		buffer -= namelen;
+		memcpy(buffer, dentry->d_name.name, namelen);
+		*--buffer = '/';
 		dentry = parent;
 	}
+	/* Get '/' right. */
+	if (*buffer != '/')
+		*--buffer = '/';
 
-	return retval;
+out:
+	spin_unlock(&dcache_lock);
+	return buffer;
 
 global_root:
+	/*
+	 * We went past the (vfsmount, dentry) we were looking for and have
+	 * either hit a root dentry, a lazily unmounted dentry, an
+	 * unconnected dentry, or the file is on a pseudo filesystem.
+	 */
 	namelen = dentry->d_name.len;
-	buflen -= namelen;
-	if (buflen < 0)
+	is_slash = (namelen == 1 && *dentry->d_name.name == '/');
+	if (is_slash || (dentry->d_sb->s_flags & MS_NOUSER)) {
+		/*
+		 * Make sure we won't return a pathname starting with '/'.
+		 *
+		 * Historically, we also glue together the root dentry and
+		 * remaining name for pseudo filesystems like pipefs, which
+		 * have the MS_NOUSER flag set. This results in pathnames
+		 * like "pipe:[439336]".
+		 */
+		if (*buffer == '/') {
+			buffer++;
+			buflen++;
+		}
+		if (is_slash) {
+			if (*buffer == '\0')
+				*--buffer = '.';
+			goto out;
+		}
+	}
+	if (buflen < namelen)
 		goto Elong;
-	retval -= namelen-1;	/* hit the slash */
-	memcpy(retval, dentry->d_name.name, namelen);
-	return retval;
+	buffer -= namelen;
+	memcpy(buffer, dentry->d_name.name, namelen);
+	goto out;
+
 Elong:
-	return ERR_PTR(-ENAMETOOLONG);
+	buffer = ERR_PTR(-ENAMETOOLONG);
+	goto out;
 }
 
 /* write full pathname into buffer and return start of pathname */
-char * d_path(struct dentry *dentry, struct vfsmount *vfsmnt,
-				char *buf, int buflen)
+char *d_path(struct dentry *dentry, struct vfsmount *vfsmnt, char *buf,
+	     int buflen)
 {
 	char *res;
 	struct vfsmount *rootmnt;
@@ -1827,9 +1856,7 @@ char * d_path(struct dentry *dentry, str
 	rootmnt = mntget(current->fs->rootmnt);
 	root = dget(current->fs->root);
 	read_unlock(&current->fs->lock);
-	spin_lock(&dcache_lock);
-	res = __d_path(dentry, vfsmnt, root, rootmnt, buf, buflen);
-	spin_unlock(&dcache_lock);
+	res = __d_path(dentry, vfsmnt, root, rootmnt, buf, buflen, 0);
 	dput(root);
 	mntput(rootmnt);
 	return res;
@@ -1855,10 +1882,10 @@ char * d_path(struct dentry *dentry, str
  */
 asmlinkage long sys_getcwd(char __user *buf, unsigned long size)
 {
-	int error;
+	int error, len;
 	struct vfsmount *pwdmnt, *rootmnt;
 	struct dentry *pwd, *root;
-	char *page = (char *) __get_free_page(GFP_USER);
+	char *page = (char *) __get_free_page(GFP_USER), *cwd;
 
 	if (!page)
 		return -ENOMEM;
@@ -1870,29 +1897,21 @@ asmlinkage long sys_getcwd(char __user *
 	root = dget(current->fs->root);
 	read_unlock(&current->fs->lock);
 
+	cwd = __d_path(pwd, pwdmnt, root, rootmnt, page, PAGE_SIZE, 1);
+	error = PTR_ERR(cwd);
+	if (IS_ERR(cwd))
+		goto out;
 	error = -ENOENT;
-	/* Has the current directory has been unlinked? */
-	spin_lock(&dcache_lock);
-	if (pwd->d_parent == pwd || !d_unhashed(pwd)) {
-		unsigned long len;
-		char * cwd;
-
-		cwd = __d_path(pwd, pwdmnt, root, rootmnt, page, PAGE_SIZE);
-		spin_unlock(&dcache_lock);
-
-		error = PTR_ERR(cwd);
-		if (IS_ERR(cwd))
-			goto out;
+	if (*cwd != '/')
+		goto out;
 
-		error = -ERANGE;
-		len = PAGE_SIZE + page - cwd;
-		if (len <= size) {
-			error = len;
-			if (copy_to_user(buf, cwd, len))
-				error = -EFAULT;
-		}
-	} else
-		spin_unlock(&dcache_lock);
+	error = -ERANGE;
+	len = PAGE_SIZE + page - cwd;
+	if (len <= size) {
+		error = len;
+		if (copy_to_user(buf, cwd, len))
+			error = -EFAULT;
+	}
 
 out:
 	dput(pwd);
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -348,8 +348,16 @@ static inline void mangle(struct seq_fil
 	seq_escape(m, s, " \t\n\\");
 }
 
+/* Keep in sync with fs/proc/base.c! */
+struct proc_mounts {
+        struct seq_file m;
+        void *page;
+        int event;
+};
+
 static int show_vfsmnt(struct seq_file *m, void *v)
 {
+	void *page = container_of(m, struct proc_mounts, m)->page;
 	struct vfsmount *mnt = v;
 	int err = 0;
 	static struct proc_fs_info {
@@ -371,10 +379,15 @@ static int show_vfsmnt(struct seq_file *
 		{ 0, NULL }
 	};
 	struct proc_fs_info *fs_infop;
+	char *path;
+
+	path = d_path(mnt->mnt_root, mnt, page, PAGE_SIZE);
+	if (IS_ERR(path) || *path != '/')
+		return err;
 
 	mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none");
 	seq_putc(m, ' ');
-	seq_path(m, mnt, mnt->mnt_root, " \t\n\\");
+	mangle(m, path);
 	seq_putc(m, ' ');
 	mangle(m, mnt->mnt_sb->s_type->name);
 	seq_puts(m, mnt->mnt_sb->s_flags & MS_RDONLY ? " ro" : " rw");
@@ -401,8 +414,14 @@ struct seq_operations mounts_op = {
 
 static int show_vfsstat(struct seq_file *m, void *v)
 {
+	void *page = container_of(m, struct proc_mounts, m)->page;
 	struct vfsmount *mnt = v;
 	int err = 0;
+	char *path;
+
+	path = d_path(mnt->mnt_root, mnt, page, PAGE_SIZE);
+	if (IS_ERR(path) || *path != '/')
+		return err; /* error or path unreachable from chroot */
 
 	/* device */
 	if (mnt->mnt_devname) {
@@ -413,7 +432,7 @@ static int show_vfsstat(struct seq_file 
 
 	/* mount point */
 	seq_puts(m, " mounted on ");
-	seq_path(m, mnt, mnt->mnt_root, " \t\n\\");
+	mangle(m, path);
 	seq_putc(m, ' ');
 
 	/* file system type */
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -353,13 +353,16 @@ static const struct inode_operations pro
 	.setattr	= proc_setattr,
 };
 
+/* Keep in sync with fs/namespace.c! */
 extern struct seq_operations mounts_op;
 struct proc_mounts {
 	struct seq_file m;
+	void *page;
 	int event;
 };
 
-static int mounts_open(struct inode *inode, struct file *file)
+static int __mounts_open(struct inode *inode, struct file *file,
+			 struct seq_operations *seq_ops)
 {
 	struct task_struct *task = get_proc_task(inode);
 	struct mnt_namespace *ns = NULL;
@@ -382,12 +385,16 @@ static int mounts_open(struct inode *ino
 		p = kmalloc(sizeof(struct proc_mounts), GFP_KERNEL);
 		if (p) {
 			file->private_data = &p->m;
-			ret = seq_open(file, &mounts_op);
+			p->page = (void *)__get_free_page(GFP_KERNEL);
+			if (p->page)
+				ret = seq_open(file, seq_ops);
 			if (!ret) {
 				p->m.private = ns;
 				p->event = ns->event;
 				return 0;
 			}
+			if (p->page)
+				free_page((unsigned long)p->page);
 			kfree(p);
 		}
 		put_mnt_ns(ns);
@@ -395,17 +402,26 @@ static int mounts_open(struct inode *ino
 	return ret;
 }
 
+static int mounts_open(struct inode *inode, struct file *file)
+{
+	return __mounts_open(inode, file, &mounts_op);
+}
+
 static int mounts_release(struct inode *inode, struct file *file)
 {
-	struct seq_file *m = file->private_data;
-	struct mnt_namespace *ns = m->private;
+	struct proc_mounts *p =
+		container_of(file->private_data, struct proc_mounts, m);
+	struct mnt_namespace *ns = p->m.private;
+
+	free_page((unsigned long)p->page);
 	put_mnt_ns(ns);
 	return seq_release(inode, file);
 }
 
 static unsigned mounts_poll(struct file *file, poll_table *wait)
 {
-	struct proc_mounts *p = file->private_data;
+	struct proc_mounts *p =
+		container_of(file->private_data, struct proc_mounts, m);
 	struct mnt_namespace *ns = p->m.private;
 	unsigned res = 0;
 
@@ -432,31 +448,7 @@ static const struct file_operations proc
 extern struct seq_operations mountstats_op;
 static int mountstats_open(struct inode *inode, struct file *file)
 {
-	int ret = seq_open(file, &mountstats_op);
-
-	if (!ret) {
-		struct seq_file *m = file->private_data;
-		struct mnt_namespace *mnt_ns = NULL;
-		struct task_struct *task = get_proc_task(inode);
-
-		if (task) {
-			task_lock(task);
-			if (task->nsproxy)
-				mnt_ns = task->nsproxy->mnt_ns;
-			if (mnt_ns)
-				get_mnt_ns(mnt_ns);
-			task_unlock(task);
-			put_task_struct(task);
-		}
-
-		if (mnt_ns)
-			m->private = mnt_ns;
-		else {
-			seq_release(inode, file);
-			ret = -EINVAL;
-		}
-	}
-	return ret;
+	return __mounts_open(inode, file, &mountstats_op);
 }
 
 static const struct file_operations proc_mountstats_operations = {

-- 

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

* [AppArmor 32/41] Make d_path() consistent across mount operations
  2007-04-12  9:08 [AppArmor 00/41] AppArmor security module overview jjohansen
                   ` (30 preceding siblings ...)
  2007-04-12  9:08 ` [AppArmor 31/41] Fix __d_path() for lazy unmounts and make it unambiguous; exclude unreachable mount points from /proc/mounts jjohansen
@ 2007-04-12  9:08 ` jjohansen
  2007-04-12  9:08 ` [AppArmor 33/41] Add d_namespace_path() to obtain namespace relative pathnames jjohansen
                   ` (11 subsequent siblings)
  43 siblings, 0 replies; 187+ messages in thread
From: jjohansen @ 2007-04-12  9:08 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, linux-fsdevel, chrisw, Andreas Gruenbacher

[-- Attachment #1: mount-consistent-d_path.diff --]
[-- Type: text/plain, Size: 1823 bytes --]

Right now, the path that __d_path() computes can become slightly
inconsistent when it races with mount operations: it grabs the
vfsmount_lock when traversing mount points, but immediately drops it
again, only to re-grab it when it reaches the next mount point.
The result is that the filename computed is not always consisent, and
the file may never have had that name. (This is unlikely, but still
possible.)

We can easily fix this by grabbing the vfsmount_lock when the first
mount point is reached, and holding onto it until the d_cache lookup is
completed.

Signed-off-by: Andreas Gruenbacher <agruen@suse.de>

---
 fs/dcache.c |   14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1754,7 +1754,7 @@ static char *__d_path(struct dentry *den
 		      struct dentry *root, struct vfsmount *rootmnt,
 		      char *buffer, int buflen, int fail_deleted)
 {
-	int namelen, is_slash;
+	int namelen, is_slash, vfsmount_locked = 0;
 
 	if (buflen < 2)
 		return ERR_PTR(-ENAMETOOLONG);
@@ -1777,14 +1777,14 @@ static char *__d_path(struct dentry *den
 		struct dentry * parent;
 
 		if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
-			spin_lock(&vfsmount_lock);
-			if (vfsmnt->mnt_parent == vfsmnt) {
-				spin_unlock(&vfsmount_lock);
-				goto global_root;
+			if (!vfsmount_locked) {
+				spin_lock(&vfsmount_lock);
+				vfsmount_locked = 1;
 			}
+			if (vfsmnt->mnt_parent == vfsmnt)
+				goto global_root;
 			dentry = vfsmnt->mnt_mountpoint;
 			vfsmnt = vfsmnt->mnt_parent;
-			spin_unlock(&vfsmount_lock);
 			continue;
 		}
 		parent = dentry->d_parent;
@@ -1803,6 +1803,8 @@ static char *__d_path(struct dentry *den
 		*--buffer = '/';
 
 out:
+	if (vfsmount_locked)
+		spin_unlock(&vfsmount_lock);
 	spin_unlock(&dcache_lock);
 	return buffer;
 

-- 

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

* [AppArmor 33/41] Add d_namespace_path() to obtain namespace relative pathnames
  2007-04-12  9:08 [AppArmor 00/41] AppArmor security module overview jjohansen
                   ` (31 preceding siblings ...)
  2007-04-12  9:08 ` [AppArmor 32/41] Make d_path() consistent across mount operations jjohansen
@ 2007-04-12  9:08 ` jjohansen
  2007-04-12 10:49   ` Al Viro
  2007-04-12  9:08 ` [AppArmor 34/41] Enable LSM hooks to distinguish operations on file descriptors from operations on pathnames jjohansen
                   ` (10 subsequent siblings)
  43 siblings, 1 reply; 187+ messages in thread
From: jjohansen @ 2007-04-12  9:08 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, linux-fsdevel, chrisw, Andreas Gruenbacher

[-- Attachment #1: d_namespace_path.diff --]
[-- Type: text/plain, Size: 2572 bytes --]

In AppArmor we are interested in pathnames relative to the namespace
root. Except for the root where the search ends, this is the same as
d_path(). Add d_namespace_path() for that.
internals.

Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Reviewed-by: John Johansen <jjohansen@suse.de>

---
 fs/dcache.c            |    6 +++---
 fs/namespace.c         |   22 ++++++++++++++++++++++
 include/linux/dcache.h |    2 ++
 include/linux/mount.h  |    2 ++
 4 files changed, 29 insertions(+), 3 deletions(-)

--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1750,9 +1750,9 @@ shouldnt_be_hashed:
  *
  * Returns the buffer or an error code.
  */
-static char *__d_path(struct dentry *dentry, struct vfsmount *vfsmnt,
-		      struct dentry *root, struct vfsmount *rootmnt,
-		      char *buffer, int buflen, int fail_deleted)
+char *__d_path(struct dentry *dentry, struct vfsmount *vfsmnt,
+	       struct dentry *root, struct vfsmount *rootmnt,
+	       char *buffer, int buflen, int fail_deleted)
 {
 	int namelen, is_slash, vfsmount_locked = 0;
 
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -1896,3 +1896,25 @@ void __put_mnt_ns(struct mnt_namespace *
 	release_mounts(&umount_list);
 	kfree(ns);
 }
+
+char *d_namespace_path(struct dentry *dentry, struct vfsmount *vfsmnt,
+		       char *buf, int buflen)
+{
+	char *res;
+	struct vfsmount *rootmnt, *nsrootmnt;
+	struct dentry *root;
+
+	read_lock(&current->fs->lock);
+	rootmnt = mntget(current->fs->rootmnt);
+	read_unlock(&current->fs->lock);
+	spin_lock(&vfsmount_lock);
+	nsrootmnt = mntget(rootmnt->mnt_ns->root);
+	root = dget(nsrootmnt->mnt_root);
+	spin_unlock(&vfsmount_lock);
+	mntput(rootmnt);
+	res = __d_path(dentry, vfsmnt, root, nsrootmnt, buf, buflen, 1);
+	dput(root);
+	mntput(nsrootmnt);
+	return res;
+}
+EXPORT_SYMBOL(d_namespace_path);
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -293,6 +293,8 @@ extern struct dentry * d_hash_and_lookup
 /* validate "insecure" dentry pointer */
 extern int d_validate(struct dentry *, struct dentry *);
 
+extern char *__d_path(struct dentry *, struct vfsmount *, struct dentry *,
+		      struct vfsmount *, char *, int, int);
 extern char * d_path(struct dentry *, struct vfsmount *, char *, int);
   
 /* Allocation counts.. */
--- a/include/linux/mount.h
+++ b/include/linux/mount.h
@@ -103,5 +103,7 @@ extern void shrink_submounts(struct vfsm
 extern spinlock_t vfsmount_lock;
 extern dev_t name_to_dev_t(char *name);
 
+extern char *d_namespace_path(struct dentry *, struct vfsmount *, char *, int);
+
 #endif
 #endif /* _LINUX_MOUNT_H */

-- 

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

* [AppArmor 34/41] Enable LSM hooks to distinguish operations on file descriptors from operations on pathnames.
  2007-04-12  9:08 [AppArmor 00/41] AppArmor security module overview jjohansen
                   ` (32 preceding siblings ...)
  2007-04-12  9:08 ` [AppArmor 33/41] Add d_namespace_path() to obtain namespace relative pathnames jjohansen
@ 2007-04-12  9:08 ` jjohansen
  2007-04-12  9:08 ` [AppArmor 35/41] Pass struct file down the inode_*xattr security LSM hooks jjohansen
                   ` (9 subsequent siblings)
  43 siblings, 0 replies; 187+ messages in thread
From: jjohansen @ 2007-04-12  9:08 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, linux-fsdevel, chrisw,
	Andreas Gruenbacher, John Johansen, Miklos Szeredi

[-- Attachment #1: file-handle-ops.diff --]
[-- Type: text/plain, Size: 4416 bytes --]

Struct iattr already contains ia_file since commit cc4e69de from 
Miklos (which is related to commit befc649c). Use this to pass
struct file down the setattr hooks. This allows LSMs to distinguish
operations on file descriptors from operations on paths.

Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>
Cc: Miklos Szeredi <mszeredi@suse.cz>

---
 fs/nfsd/vfs.c      |   11 ++++++-----
 fs/open.c          |   16 +++++++++++-----
 include/linux/fs.h |    3 +++
 3 files changed, 20 insertions(+), 10 deletions(-)

--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -383,7 +383,7 @@ static ssize_t nfsd_getxattr(struct dent
 {
 	ssize_t buflen;
 
-	buflen = vfs_getxattr(dentry, mnt, key, NULL, 0);
+	buflen = vfs_getxattr(dentry, mnt, key, NULL, 0, NULL);
 	if (buflen <= 0)
 		return buflen;
 
@@ -391,7 +391,7 @@ static ssize_t nfsd_getxattr(struct dent
 	if (!*buf)
 		return -ENOMEM;
 
-	return vfs_getxattr(dentry, mnt, key, *buf, buflen);
+	return vfs_getxattr(dentry, mnt, key, *buf, buflen, NULL);
 }
 #endif
 
@@ -417,7 +417,7 @@ set_nfsv4_acl_one(struct dentry *dentry,
 		goto out;
 	}
 
-	error = vfs_setxattr(dentry, mnt, key, buf, len, 0);
+	error = vfs_setxattr(dentry, mnt, key, buf, len, 0, NULL);
 out:
 	kfree(buf);
 	return error;
@@ -1987,13 +1987,14 @@ nfsd_set_posix_acl(struct svc_fh *fhp, i
 
 	if (size)
 		error = vfs_setxattr(fhp->fh_dentry, fhp->fh_export->ex_mnt,
-				     name, value, size,0);
+				     name, value, size, 0, NULL);
 	else {
 		if (!S_ISDIR(inode->i_mode) && type == ACL_TYPE_DEFAULT)
 			error = 0;
 		else {
 			error = vfs_removexattr(fhp->fh_dentry,
-						fhp->fh_export->ex_mnt, name);
+						fhp->fh_export->ex_mnt, name,
+						NULL);
 			if (error == -ENODATA)
 				error = 0;
 		}
--- a/fs/open.c
+++ b/fs/open.c
@@ -520,6 +520,8 @@ asmlinkage long sys_fchmod(unsigned int 
 		mode = inode->i_mode;
 	newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
 	newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
+	newattrs.ia_valid |= ATTR_FILE;
+	newattrs.ia_file = file;
 	err = notify_change(dentry, file->f_path.mnt, &newattrs);
 	mutex_unlock(&inode->i_mutex);
 
@@ -570,7 +572,7 @@ asmlinkage long sys_chmod(const char __u
 }
 
 static int chown_common(struct dentry * dentry, struct vfsmount *mnt,
-			uid_t user, gid_t group)
+			uid_t user, gid_t group, struct file *file)
 {
 	struct inode * inode;
 	int error;
@@ -598,6 +600,10 @@ static int chown_common(struct dentry * 
 	}
 	if (!S_ISDIR(inode->i_mode))
 		newattrs.ia_valid |= ATTR_KILL_SUID|ATTR_KILL_SGID;
+	if (file) {
+		newattrs.ia_file = file;
+		newattrs.ia_valid |= ATTR_FILE;
+	}
 	mutex_lock(&inode->i_mutex);
 	error = notify_change(dentry, mnt, &newattrs);
 	mutex_unlock(&inode->i_mutex);
@@ -613,7 +619,7 @@ asmlinkage long sys_chown(const char __u
 	error = user_path_walk(filename, &nd);
 	if (error)
 		goto out;
-	error = chown_common(nd.dentry, nd.mnt, user, group);
+	error = chown_common(nd.dentry, nd.mnt, user, group, NULL);
 	path_release(&nd);
 out:
 	return error;
@@ -633,7 +639,7 @@ asmlinkage long sys_fchownat(int dfd, co
 	error = __user_walk_fd(dfd, filename, follow, &nd);
 	if (error)
 		goto out;
-	error = chown_common(nd.dentry, nd.mnt, user, group);
+	error = chown_common(nd.dentry, nd.mnt, user, group, NULL);
 	path_release(&nd);
 out:
 	return error;
@@ -647,7 +653,7 @@ asmlinkage long sys_lchown(const char __
 	error = user_path_walk_link(filename, &nd);
 	if (error)
 		goto out;
-	error = chown_common(nd.dentry, nd.mnt, user, group);
+	error = chown_common(nd.dentry, nd.mnt, user, group, NULL);
 	path_release(&nd);
 out:
 	return error;
@@ -666,7 +672,7 @@ asmlinkage long sys_fchown(unsigned int 
 
 	dentry = file->f_path.dentry;
 	audit_inode(NULL, dentry->d_inode);
-	error = chown_common(dentry, file->f_path.mnt, user, group);
+	error = chown_common(dentry, file->f_path.mnt, user, group, file);
 	fput(file);
 out:
 	return error;
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -349,6 +349,9 @@ struct iattr {
 	 * Not an attribute, but an auxilary info for filesystems wanting to
 	 * implement an ftruncate() like method.  NOTE: filesystem should
 	 * check for (ia_valid & ATTR_FILE), and not for (ia_file != NULL).
+	 *
+	 * The LSM hooks also use this to distinguish operations on a file
+	 * descriptors from operations on pathnames.
 	 */
 	struct file	*ia_file;
 };

-- 

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

* [AppArmor 35/41] Pass struct file down the inode_*xattr security LSM hooks
  2007-04-12  9:08 [AppArmor 00/41] AppArmor security module overview jjohansen
                   ` (33 preceding siblings ...)
  2007-04-12  9:08 ` [AppArmor 34/41] Enable LSM hooks to distinguish operations on file descriptors from operations on pathnames jjohansen
@ 2007-04-12  9:08 ` jjohansen
  2007-04-12  9:08 ` [AppArmor 36/41] Export audit subsystem for use by modules jjohansen
                   ` (8 subsequent siblings)
  43 siblings, 0 replies; 187+ messages in thread
From: jjohansen @ 2007-04-12  9:08 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, linux-fsdevel, chrisw,
	Andreas Gruenbacher, John Johansen

[-- Attachment #1: security-xattr-file.diff --]
[-- Type: text/plain, Size: 16561 bytes --]

This allows LSMs to also distinguish between file descriptor and path
access for the xattr operations. (The other relevant operations are
covered by the setattr hook.)

Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>

---
 fs/xattr.c               |   58 ++++++++++++++++++++++++-----------------------
 include/linux/security.h |   37 +++++++++++++++++------------
 include/linux/xattr.h    |    8 +++---
 security/commoncap.c     |    4 +--
 security/dummy.c         |   10 ++++----
 security/selinux/hooks.c |   10 ++++----
 6 files changed, 70 insertions(+), 57 deletions(-)

--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -71,7 +71,7 @@ xattr_permission(struct inode *inode, co
 
 int
 vfs_setxattr(struct dentry *dentry, struct vfsmount *mnt, char *name,
-	     void *value, size_t size, int flags)
+	     void *value, size_t size, int flags, struct file *file)
 {
 	struct inode *inode = dentry->d_inode;
 	int error;
@@ -81,7 +81,7 @@ vfs_setxattr(struct dentry *dentry, stru
 		return error;
 
 	mutex_lock(&inode->i_mutex);
-	error = security_inode_setxattr(dentry, mnt, name, value, size, flags);
+	error = security_inode_setxattr(dentry, mnt, name, value, size, flags,						file);
 	if (error)
 		goto out;
 	error = -EOPNOTSUPP;
@@ -108,7 +108,7 @@ EXPORT_SYMBOL_GPL(vfs_setxattr);
 
 ssize_t
 vfs_getxattr(struct dentry *dentry, struct vfsmount *mnt, char *name,
-	     void *value, size_t size)
+	     void *value, size_t size, struct file *file)
 {
 	struct inode *inode = dentry->d_inode;
 	int error;
@@ -117,7 +117,7 @@ vfs_getxattr(struct dentry *dentry, stru
 	if (error)
 		return error;
 
-	error = security_inode_getxattr(dentry, mnt, name);
+	error = security_inode_getxattr(dentry, mnt, name, file);
 	if (error)
 		return error;
 
@@ -145,12 +145,12 @@ EXPORT_SYMBOL_GPL(vfs_getxattr);
 
 ssize_t
 vfs_listxattr(struct dentry *dentry, struct vfsmount *mnt, char *list,
-	      size_t size)
+	      size_t size, struct file *file)
 {
 	struct inode *inode = dentry->d_inode;
 	ssize_t error;
 
-	error = security_inode_listxattr(dentry, mnt);
+	error = security_inode_listxattr(dentry, mnt, file);
 	if (error)
 		return error;
 	error = -EOPNOTSUPP;
@@ -166,7 +166,8 @@ vfs_listxattr(struct dentry *dentry, str
 EXPORT_SYMBOL_GPL(vfs_listxattr);
 
 int
-vfs_removexattr(struct dentry *dentry, struct vfsmount *mnt, char *name)
+vfs_removexattr(struct dentry *dentry, struct vfsmount *mnt, char *name,
+		struct file *file)
 {
 	struct inode *inode = dentry->d_inode;
 	int error;
@@ -178,7 +179,7 @@ vfs_removexattr(struct dentry *dentry, s
 	if (error)
 		return error;
 
-	error = security_inode_removexattr(dentry, mnt, name);
+	error = security_inode_removexattr(dentry, mnt, name, file);
 	if (error)
 		return error;
 
@@ -198,7 +199,7 @@ EXPORT_SYMBOL_GPL(vfs_removexattr);
  */
 static long
 setxattr(struct dentry *dentry, struct vfsmount *mnt, char __user *name,
-	 void __user *value, size_t size, int flags)
+	 void __user *value, size_t size, int flags, struct file *file)
 {
 	int error;
 	void *kvalue = NULL;
@@ -225,7 +226,7 @@ setxattr(struct dentry *dentry, struct v
 		}
 	}
 
-	error = vfs_setxattr(dentry, mnt, kname, kvalue, size, flags);
+	error = vfs_setxattr(dentry, mnt, kname, kvalue, size, flags, file);
 	kfree(kvalue);
 	return error;
 }
@@ -240,7 +241,7 @@ sys_setxattr(char __user *path, char __u
 	error = user_path_walk(path, &nd);
 	if (error)
 		return error;
-	error = setxattr(nd.dentry, nd.mnt, name, value, size, flags);
+	error = setxattr(nd.dentry, nd.mnt, name, value, size, flags, NULL);
 	path_release(&nd);
 	return error;
 }
@@ -255,7 +256,7 @@ sys_lsetxattr(char __user *path, char __
 	error = user_path_walk_link(path, &nd);
 	if (error)
 		return error;
-	error = setxattr(nd.dentry, nd.mnt, name, value, size, flags);
+	error = setxattr(nd.dentry, nd.mnt, name, value, size, flags, NULL);
 	path_release(&nd);
 	return error;
 }
@@ -273,7 +274,7 @@ sys_fsetxattr(int fd, char __user *name,
 		return error;
 	dentry = f->f_path.dentry;
 	audit_inode(NULL, dentry->d_inode);
-	error = setxattr(dentry, f->f_vfsmnt, name, value, size, flags);
+	error = setxattr(dentry, f->f_vfsmnt, name, value, size, flags, f);
 	fput(f);
 	return error;
 }
@@ -283,7 +284,7 @@ sys_fsetxattr(int fd, char __user *name,
  */
 static ssize_t
 getxattr(struct dentry *dentry, struct vfsmount *mnt, char __user *name,
-	 void __user *value, size_t size)
+	 void __user *value, size_t size, struct file *file)
 {
 	ssize_t error;
 	void *kvalue = NULL;
@@ -303,7 +304,7 @@ getxattr(struct dentry *dentry, struct v
 			return -ENOMEM;
 	}
 
-	error = vfs_getxattr(dentry, mnt, kname, kvalue, size);
+	error = vfs_getxattr(dentry, mnt, kname, kvalue, size, file);
 	if (error > 0) {
 		if (size && copy_to_user(value, kvalue, error))
 			error = -EFAULT;
@@ -326,7 +327,7 @@ sys_getxattr(char __user *path, char __u
 	error = user_path_walk(path, &nd);
 	if (error)
 		return error;
-	error = getxattr(nd.dentry, nd.mnt, name, value, size);
+	error = getxattr(nd.dentry, nd.mnt, name, value, size, NULL);
 	path_release(&nd);
 	return error;
 }
@@ -341,7 +342,7 @@ sys_lgetxattr(char __user *path, char __
 	error = user_path_walk_link(path, &nd);
 	if (error)
 		return error;
-	error = getxattr(nd.dentry, nd.mnt, name, value, size);
+	error = getxattr(nd.dentry, nd.mnt, name, value, size, NULL);
 	path_release(&nd);
 	return error;
 }
@@ -355,7 +356,7 @@ sys_fgetxattr(int fd, char __user *name,
 	f = fget(fd);
 	if (!f)
 		return error;
-	error = getxattr(f->f_path.dentry, f->f_path.mnt, name, value, size);
+	error = getxattr(f->f_path.dentry, f->f_path.mnt, name, value, size, f);
 	fput(f);
 	return error;
 }
@@ -365,7 +366,7 @@ sys_fgetxattr(int fd, char __user *name,
  */
 static ssize_t
 listxattr(struct dentry *dentry, struct vfsmount *mnt, char __user *list,
-	  size_t size)
+	  size_t size, struct file *file)
 {
 	ssize_t error;
 	char *klist = NULL;
@@ -378,7 +379,7 @@ listxattr(struct dentry *dentry, struct 
 			return -ENOMEM;
 	}
 
-	error = vfs_listxattr(dentry, mnt, klist, size);
+	error = vfs_listxattr(dentry, mnt, klist, size, file);
 	if (error > 0) {
 		if (size && copy_to_user(list, klist, error))
 			error = -EFAULT;
@@ -400,7 +401,7 @@ sys_listxattr(char __user *path, char __
 	error = user_path_walk(path, &nd);
 	if (error)
 		return error;
-	error = listxattr(nd.dentry, nd.mnt, list, size);
+	error = listxattr(nd.dentry, nd.mnt, list, size, NULL);
 	path_release(&nd);
 	return error;
 }
@@ -414,7 +415,7 @@ sys_llistxattr(char __user *path, char _
 	error = user_path_walk_link(path, &nd);
 	if (error)
 		return error;
-	error = listxattr(nd.dentry, nd.mnt, list, size);
+	error = listxattr(nd.dentry, nd.mnt, list, size, NULL);
 	path_release(&nd);
 	return error;
 }
@@ -428,7 +429,7 @@ sys_flistxattr(int fd, char __user *list
 	f = fget(fd);
 	if (!f)
 		return error;
-	error = listxattr(f->f_path.dentry, f->f_path.mnt, list, size);
+	error = listxattr(f->f_path.dentry, f->f_path.mnt, list, size, f);
 	fput(f);
 	return error;
 }
@@ -437,7 +438,8 @@ sys_flistxattr(int fd, char __user *list
  * Extended attribute REMOVE operations
  */
 static long
-removexattr(struct dentry *dentry, struct vfsmount *mnt, char __user *name)
+removexattr(struct dentry *dentry, struct vfsmount *mnt, char __user *name,
+	    struct file *file)
 {
 	int error;
 	char kname[XATTR_NAME_MAX + 1];
@@ -448,7 +450,7 @@ removexattr(struct dentry *dentry, struc
 	if (error < 0)
 		return error;
 
-	return vfs_removexattr(dentry, mnt, kname);
+	return vfs_removexattr(dentry, mnt, kname, file);
 }
 
 asmlinkage long
@@ -460,7 +462,7 @@ sys_removexattr(char __user *path, char 
 	error = user_path_walk(path, &nd);
 	if (error)
 		return error;
-	error = removexattr(nd.dentry, nd.mnt, name);
+	error = removexattr(nd.dentry, nd.mnt, name, NULL);
 	path_release(&nd);
 	return error;
 }
@@ -474,7 +476,7 @@ sys_lremovexattr(char __user *path, char
 	error = user_path_walk_link(path, &nd);
 	if (error)
 		return error;
-	error = removexattr(nd.dentry, nd.mnt, name);
+	error = removexattr(nd.dentry, nd.mnt, name, NULL);
 	path_release(&nd);
 	return error;
 }
@@ -491,7 +493,7 @@ sys_fremovexattr(int fd, char __user *na
 		return error;
 	dentry = f->f_path.dentry;
 	audit_inode(NULL, dentry->d_inode);
-	error = removexattr(dentry, f->f_path.mnt, name);
+	error = removexattr(dentry, f->f_path.mnt, name, f);
 	fput(f);
 	return error;
 }
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -49,8 +49,8 @@ extern void cap_capset_set (struct task_
 extern int cap_bprm_set_security (struct linux_binprm *bprm);
 extern void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe);
 extern int cap_bprm_secureexec(struct linux_binprm *bprm);
-extern int cap_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt, char *name, void *value, size_t size, int flags);
-extern int cap_inode_removexattr(struct dentry *dentry, struct vfsmount *mnt, char *name);
+extern int cap_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt, char *name, void *value, size_t size, int flags, struct file *file);
+extern int cap_inode_removexattr(struct dentry *dentry, struct vfsmount *mnt, char *name, struct file *file);
 extern int cap_task_post_setuid (uid_t old_ruid, uid_t old_euid, uid_t old_suid, int flags);
 extern void cap_task_reparent_to_init (struct task_struct *p);
 extern int cap_syslog (int type);
@@ -1243,16 +1243,18 @@ struct security_operations {
 	int (*inode_getattr) (struct vfsmount *mnt, struct dentry *dentry);
         void (*inode_delete) (struct inode *inode);
 	int (*inode_setxattr) (struct dentry *dentry, struct vfsmount *mnt,
-			       char *name, void *value, size_t size, int flags);
+			       char *name, void *value, size_t size, int flags,
+			       struct file *file);
 	void (*inode_post_setxattr) (struct dentry *dentry,
 				     struct vfsmount *mnt,
 				     char *name, void *value,
 				     size_t size, int flags);
 	int (*inode_getxattr) (struct dentry *dentry, struct vfsmount *mnt,
-			       char *name);
-	int (*inode_listxattr) (struct dentry *dentry, struct vfsmount *mnt);
+			       char *name, struct file *file);
+	int (*inode_listxattr) (struct dentry *dentry, struct vfsmount *mnt,
+				struct file *file);
 	int (*inode_removexattr) (struct dentry *dentry, struct vfsmount *mnt,
-				  char *name);
+				  char *name, struct file *file);
 	const char *(*inode_xattr_getsuffix) (void);
   	int (*inode_getsecurity)(const struct inode *inode, const char *name, void *buffer, size_t size, int err);
   	int (*inode_setsecurity)(struct inode *inode, const char *name, const void *value, size_t size, int flags);
@@ -1766,12 +1768,13 @@ static inline void security_inode_delete
 
 static inline int security_inode_setxattr (struct dentry *dentry,
 					   struct vfsmount *mnt, char *name,
-					   void *value, size_t size, int flags)
+					   void *value, size_t size, int flags,
+					   struct file *file)
 {
 	if (unlikely (IS_PRIVATE (dentry->d_inode)))
 		return 0;
 	return security_ops->inode_setxattr (dentry, mnt, name, value, size,
-					     flags);
+					     flags, file);
 }
 
 static inline void security_inode_post_setxattr (struct dentry *dentry,
@@ -1781,31 +1784,35 @@ static inline void security_inode_post_s
 {
 	if (unlikely (IS_PRIVATE (dentry->d_inode)))
 		return;
-	security_ops->inode_post_setxattr (dentry, mnt, name, value, size, flags);
+	security_ops->inode_post_setxattr (dentry, mnt, name, value, size,
+					   flags);
 }
 
 static inline int security_inode_getxattr (struct dentry *dentry,
-					    struct vfsmount *mnt, char *name)
+					   struct vfsmount *mnt, char *name,
+					   struct file *file)
 {
 	if (unlikely (IS_PRIVATE (dentry->d_inode)))
 		return 0;
-	return security_ops->inode_getxattr (dentry, mnt, name);
+	return security_ops->inode_getxattr (dentry, mnt, name, file);
 }
 
 static inline int security_inode_listxattr (struct dentry *dentry,
-					    struct vfsmount *mnt)
+					    struct vfsmount *mnt,
+					    struct file *file)
 {
 	if (unlikely (IS_PRIVATE (dentry->d_inode)))
 		return 0;
-	return security_ops->inode_listxattr (dentry, mnt);
+	return security_ops->inode_listxattr (dentry, mnt, file);
 }
 
 static inline int security_inode_removexattr (struct dentry *dentry,
-					      struct vfsmount *mnt, char *name)
+					      struct vfsmount *mnt, char *name,
+					      struct file *file)
 {
 	if (unlikely (IS_PRIVATE (dentry->d_inode)))
 		return 0;
-	return security_ops->inode_removexattr (dentry, mnt, name);
+	return security_ops->inode_removexattr (dentry, mnt, name, file);
 }
 
 static inline const char *security_inode_xattr_getsuffix(void)
--- a/include/linux/xattr.h
+++ b/include/linux/xattr.h
@@ -47,12 +47,12 @@ struct xattr_handler {
 };
 
 ssize_t vfs_getxattr(struct dentry *, struct vfsmount *, char *, void *,
-		     size_t);
+		     size_t, struct file *);
 ssize_t vfs_listxattr(struct dentry *d, struct vfsmount *, char *list,
-		      size_t size);
+		      size_t size, struct file *);
 int vfs_setxattr(struct dentry *, struct vfsmount *, char *, void *, size_t,
-		 int);
-int vfs_removexattr(struct dentry *, struct vfsmount *, char *);
+		 int, struct file *);
+int vfs_removexattr(struct dentry *, struct vfsmount *, char *, struct file *);
 
 ssize_t generic_getxattr(struct dentry *dentry, const char *name, void *buffer, size_t size);
 ssize_t generic_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size);
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -192,7 +192,7 @@ int cap_bprm_secureexec (struct linux_bi
 }
 
 int cap_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt, char *name,
-		       void *value, size_t size, int flags)
+		       void *value, size_t size, int flags, struct file *file)
 {
 	if (!strncmp(name, XATTR_SECURITY_PREFIX,
 		     sizeof(XATTR_SECURITY_PREFIX) - 1)  &&
@@ -202,7 +202,7 @@ int cap_inode_setxattr(struct dentry *de
 }
 
 int cap_inode_removexattr(struct dentry *dentry, struct vfsmount *mnt,
-			  char *name)
+			  char *name, struct file *file)
 {
 	if (!strncmp(name, XATTR_SECURITY_PREFIX,
 		     sizeof(XATTR_SECURITY_PREFIX) - 1)  &&
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -352,7 +352,7 @@ static void dummy_inode_delete (struct i
 
 static int dummy_inode_setxattr (struct dentry *dentry, struct vfsmount *mnt,
 				 char *name, void *value, size_t size,
-				 int flags)
+				 int flags, struct file *file)
 {
 	if (!strncmp(name, XATTR_SECURITY_PREFIX,
 		     sizeof(XATTR_SECURITY_PREFIX) - 1) &&
@@ -369,18 +369,20 @@ static void dummy_inode_post_setxattr (s
 }
 
 static int dummy_inode_getxattr (struct dentry *dentry,
-			          struct vfsmount *mnt, char *name)
+			          struct vfsmount *mnt, char *name,
+				  struct file *file)
 {
 	return 0;
 }
 
-static int dummy_inode_listxattr (struct dentry *dentry, struct vfsmount *mnt)
+static int dummy_inode_listxattr (struct dentry *dentry, struct vfsmount *mnt,
+				  struct file *file)
 {
 	return 0;
 }
 
 static int dummy_inode_removexattr (struct dentry *dentry, struct vfsmount *mnt,
-				    char *name)
+				    char *name, struct file *file)
 {
 	if (!strncmp(name, XATTR_SECURITY_PREFIX,
 		     sizeof(XATTR_SECURITY_PREFIX) - 1) &&
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2309,7 +2309,7 @@ static int selinux_inode_getattr(struct 
 
 static int selinux_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt,
 				  char *name, void *value, size_t size,
-				  int flags)
+				  int flags, struct file *file)
 {
 	struct task_security_struct *tsec = current->security;
 	struct inode *inode = dentry->d_inode;
@@ -2396,18 +2396,20 @@ static void selinux_inode_post_setxattr(
 }
 
 static int selinux_inode_getxattr (struct dentry *dentry, struct vfsmount *mnt,
-				   char *name)
+				   char *name, struct file *file)
 {
 	return dentry_has_perm(current, NULL, dentry, FILE__GETATTR);
 }
 
-static int selinux_inode_listxattr (struct dentry *dentry, struct vfsmount *mnt)
+static int selinux_inode_listxattr (struct dentry *dentry, struct vfsmount *mnt,
+				    struct file *file)
 {
 	return dentry_has_perm(current, NULL, dentry, FILE__GETATTR);
 }
 
 static int selinux_inode_removexattr (struct dentry *dentry,
-				      struct vfsmount *mnt, char *name)
+				      struct vfsmount *mnt, char *name,
+				      struct file *file)
 {
 	if (strcmp(name, XATTR_NAME_SELINUX)) {
 		if (!strncmp(name, XATTR_SECURITY_PREFIX,

-- 

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

* [AppArmor 36/41] Export audit subsystem for use by modules
  2007-04-12  9:08 [AppArmor 00/41] AppArmor security module overview jjohansen
                   ` (34 preceding siblings ...)
  2007-04-12  9:08 ` [AppArmor 35/41] Pass struct file down the inode_*xattr security LSM hooks jjohansen
@ 2007-04-12  9:08 ` jjohansen
  2007-04-12  9:08 ` [AppArmor 37/41] AppArmor: Main Part jjohansen
                   ` (7 subsequent siblings)
  43 siblings, 0 replies; 187+ messages in thread
From: jjohansen @ 2007-04-12  9:08 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, linux-fsdevel, chrisw,
	Andreas Gruenbacher, John Johansen

[-- Attachment #1: apparmor-audit.diff --]
[-- Type: text/plain, Size: 2025 bytes --]

Adds necessary export symbols for audit subsystem routines.
Changes audit_log_vformat to be externally visible (analagous to vprintf)
Patch is not in mainline -- pending AppArmor code submission to lkml

Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>

---
 include/linux/audit.h |    5 +++++
 kernel/audit.c        |    6 ++++--
 2 files changed, 9 insertions(+), 2 deletions(-)

--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -112,6 +112,8 @@
 #define AUDIT_LAST_KERN_ANOM_MSG    1799
 #define AUDIT_ANOM_PROMISCUOUS      1700 /* Device changed promiscuous mode */
 
+#define AUDIT_APPARMOR		1500	/* AppArmor audit */
+
 #define AUDIT_KERNEL		2000	/* Asynchronous audit record. NOT A REQUEST. */
 
 /* Rule flags */
@@ -488,6 +490,9 @@ extern void		    audit_log(struct audit_
 				      __attribute__((format(printf,4,5)));
 
 extern struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask, int type);
+extern void		    audit_log_vformat(struct audit_buffer *ab,
+					      const char *fmt, va_list args)
+			    __attribute__((format(printf,2,0)));
 extern void		    audit_log_format(struct audit_buffer *ab,
 					     const char *fmt, ...)
 			    __attribute__((format(printf,2,3)));
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -1054,8 +1054,7 @@ static inline int audit_expand(struct au
  * will be called a second time.  Currently, we assume that a printk
  * can't format message larger than 1024 bytes, so we don't either.
  */
-static void audit_log_vformat(struct audit_buffer *ab, const char *fmt,
-			      va_list args)
+void audit_log_vformat(struct audit_buffer *ab, const char *fmt, va_list args)
 {
 	int len, avail;
 	struct sk_buff *skb;
@@ -1311,3 +1310,6 @@ EXPORT_SYMBOL(audit_log_start);
 EXPORT_SYMBOL(audit_log_end);
 EXPORT_SYMBOL(audit_log_format);
 EXPORT_SYMBOL(audit_log);
+EXPORT_SYMBOL_GPL(audit_log_vformat);
+EXPORT_SYMBOL_GPL(audit_log_untrustedstring);
+EXPORT_SYMBOL_GPL(audit_log_d_path);

-- 

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

* [AppArmor 37/41] AppArmor: Main Part
  2007-04-12  9:08 [AppArmor 00/41] AppArmor security module overview jjohansen
                   ` (35 preceding siblings ...)
  2007-04-12  9:08 ` [AppArmor 36/41] Export audit subsystem for use by modules jjohansen
@ 2007-04-12  9:08 ` jjohansen
  2007-04-12 10:37   ` Alan Cox
  2007-04-12  9:08 ` [AppArmor 38/41] AppArmor: Module and LSM hooks jjohansen
                   ` (6 subsequent siblings)
  43 siblings, 1 reply; 187+ messages in thread
From: jjohansen @ 2007-04-12  9:08 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, linux-fsdevel, chrisw, John Johansen,
	Andreas Gruenbacher

[-- Attachment #1: apparmor-main.diff --]
[-- Type: text/plain, Size: 36414 bytes --]

The underlying functions by which the AppArmor LSM hooks are implemented.

Signed-off-by: John Johansen <jjohansen@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>

---
 security/apparmor/main.c | 1322 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 1322 insertions(+)

--- /dev/null
+++ b/security/apparmor/main.c
@@ -0,0 +1,1322 @@
+/*
+ *	Copyright (C) 2002-2007 Novell/SUSE
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License as
+ *	published by the Free Software Foundation, version 2 of the
+ *	License.
+ *
+ *	AppArmor Core
+ */
+
+#include <linux/security.h>
+#include <linux/namei.h>
+#include <linux/audit.h>
+#include <linux/mount.h>
+#include <linux/ptrace.h>
+
+#include "apparmor.h"
+
+#include "inline.h"
+
+/*
+ * Table of capability names: we generate it from capabilities.h.
+ */
+static const char *capability_names[] = {
+#include "capability_names.h"
+};
+
+/* NULL complain profile
+ *
+ * Used when in complain mode, to emit Permitting messages for non-existant
+ * profiles and hats.  This is necessary because of selective mode, in which
+ * case we need a complain null_profile and enforce null_profile
+ *
+ * The null_complain_profile cannot be statically allocated, because it
+ * can be associated to files which keep their reference even if apparmor is
+ * unloaded
+ */
+struct aa_profile *null_complain_profile;
+
+/**
+ * aa_taskattr_access
+ * @name: name of the file to check
+ *
+ * Check if name matches /proc/self/attr/current, with self resolved
+ * to the current pid. This file is the usermode iterface for
+ * changing one's hat.
+ */
+static inline int aa_taskattr_access(const char *name)
+{
+	unsigned long pid;
+	char *end;
+
+	if (strncmp(name, "/proc/", 6) != 0)
+		return 0;
+	pid = simple_strtoul(name + 6, &end, 10);
+	if (pid != current->pid)
+		return 0;
+	return strcmp(end, "/attr/current") == 0;
+}
+
+static inline void aa_permerror2result(int perm_result, struct aa_audit *sa)
+{
+	if (perm_result == 0) {	/* success */
+		sa->result = 1;
+		sa->error_code = 0;
+	} else { /* -ve internal error code or +ve mask of denied perms */
+		sa->result = 0;
+		sa->error_code = perm_result;
+	}
+}
+
+/**
+ * aa_file_denied - check for @mask access on a file
+ * @profile: profile to check against
+ * @name: pathname of file
+ * @mask: permission mask requested for file
+ *
+ * Return %0 on success, or else the permissions in @mask that the
+ * profile denies.
+ */
+static int aa_file_denied(struct aa_profile *profile, const char *name,
+			  int mask)
+{
+	int perms;
+
+	/* Always allow write access to /proc/self/attr/current. */
+	if (mask == MAY_WRITE && aa_taskattr_access(name))
+		return 0;
+
+	perms = aa_match(profile->file_rules, name);
+
+	return (mask & ~perms);
+}
+
+/**
+ * aa_link_denied - check for permission to link a file
+ * @profile: profile to check against
+ * @link: pathname of link being created
+ * @target: pathname of target to be linked to
+ *
+ * Return %0 on success, or else the permissions that the profile denies.
+ */
+static int aa_link_denied(struct aa_profile *profile, const char *link,
+			  const char *target)
+{
+	int l_mode, t_mode;
+
+	l_mode = aa_match(profile->file_rules, link);
+	t_mode = aa_match(profile->file_rules, target);
+
+	/**
+	 * Link always requires 'l' on the link, a subset of the
+	 * target's 'r', 'w', 'x', and 'm' permissions on the link, and
+	 * if the link has 'x', an exact match of all the execute flags
+	 * ('i', 'u', 'U', 'p', 'P').
+	 */
+#define RWXM (MAY_READ | MAY_WRITE | MAY_EXEC | AA_EXEC_MMAP)
+	if ((l_mode & AA_MAY_LINK) &&
+	    (l_mode & RWXM) && !(l_mode & ~t_mode & RWXM) &&
+	    (!(l_mode & MAY_EXEC) ||
+	     ((l_mode & AA_EXEC_MODIFIERS) == (t_mode & AA_EXEC_MODIFIERS) &&
+	      (l_mode & AA_EXEC_UNSAFE) == (t_mode & AA_EXEC_UNSAFE))))
+		return 0;
+#undef RWXM
+	/**
+	 * FIXME: There currenly is no way to report which permissions
+	 * we expect in t_mode, so linking could fail even after learning
+	 * the required l_mode.
+	 */
+	return AA_MAY_LINK;
+}
+
+/**
+ * aa_get_name - compute the pathname of a file
+ * @dentry: dentry of the file
+ * @mnt: vfsmount of the file
+ * @buffer: buffer that aa_get_name() allocated
+ * @check: AA_CHECK_DIR is set if the file is a directory
+ *
+ * Returns a pointer to the beginning of the pathname (which usually differs
+ * from the beginning of the buffer), or an error code.
+ *
+ * We need @check to indicate whether the file is a directory or not because
+ * the file may not yet exist, and so we cannot check the inode's file type.
+ */
+static char *aa_get_name(struct dentry *dentry, struct vfsmount *mnt,
+			 char **buffer, int check)
+{
+	char *name;
+	int is_dir, size = 256;
+
+	is_dir = (check & AA_CHECK_DIR) ? 1 : 0;
+
+	for (;;) {
+		char *buf = kmalloc(size, GFP_KERNEL);
+		if (!buf)
+			return ERR_PTR(-ENOMEM);
+
+		name = d_namespace_path(dentry, mnt, buf, size - is_dir);
+		if (!IS_ERR(name)) {
+			if (name[0] != '/') {
+				/*
+				 * This dentry is not connected to the
+				 * namespace root -- reject access.
+				 */
+				kfree(buf);
+				return ERR_PTR(-ENOENT);
+			}
+			if (is_dir && name[1] != '\0') {
+				/*
+				 * Append "/" to the pathname. The root
+				 * directory is a special case; it already
+				 * ends in slash.
+				 */
+				buf[size - 2] = '/';
+				buf[size - 1] = '\0';
+			}
+
+			*buffer = buf;
+			return name;
+		}
+		if (PTR_ERR(name) != -ENAMETOOLONG)
+			return name;
+
+		kfree(buf);
+		size <<= 1;
+		if (size > apparmor_path_max)
+			return ERR_PTR(-ENAMETOOLONG);
+	}
+}
+
+static inline void aa_put_name_buffer(char *buffer)
+{
+	kfree(buffer);
+}
+
+/**
+ * aa_perm_dentry - check if @profile allows @mask for a file
+ * @profile: profile to check against
+ * @dentry: dentry of the file
+ * @mnt: vfsmount o the file
+ * @sa: audit context
+ * @mask: requested profile permissions
+ * @check: kind of check to perform
+ *
+ * Returns 0 upon success, or else an error code.
+ *
+ * @check indicates the file type, and whether the file was accessed through
+ * an open file descriptor (AA_CHECK_FD) or not.
+ */
+static int aa_perm_dentry(struct aa_profile *profile, struct dentry *dentry,
+			  struct vfsmount *mnt, struct aa_audit *sa, int mask,
+			  int check)
+{
+	char *buffer = NULL;
+	int denied_mask, error;
+
+	sa->name = aa_get_name(dentry, mnt, &buffer, check);
+
+	if (IS_ERR(sa->name)) {
+		/*
+		 * deleted files are given a pass on permission checks when
+		 * accessed through a file descriptor.
+		 */
+		if (PTR_ERR(sa->name) == -ENOENT && (check & AA_CHECK_FD))
+			denied_mask = 0;
+		else
+			denied_mask = PTR_ERR(sa->name);
+		sa->name = NULL;
+	} else {
+		denied_mask = aa_file_denied(profile, sa->name, mask);
+	}
+
+	aa_permerror2result(denied_mask, sa);
+
+	error = aa_audit(profile, sa);
+
+	aa_put_name_buffer(buffer);
+
+	return error;
+}
+
+/**
+ * attach_nullprofile - allocate and attach a null_profile hat to profile
+ * @profile: profile to attach a null_profile hat to.
+ *
+ * Return %0 (success) or error (-%ENOMEM)
+ */
+int attach_nullprofile(struct aa_profile *profile)
+{
+	struct aa_profile *hat = NULL;
+	char *hatname = NULL;
+
+	hat = alloc_aa_profile();
+	if (!hat)
+		goto fail;
+	if (profile->flags.complain)
+		hatname = kstrdup("null-complain-profile", GFP_KERNEL);
+	else
+		hatname = kstrdup("null-profile", GFP_KERNEL);
+	if (!hatname)
+		goto fail;
+
+	hat->flags.complain = profile->flags.complain;
+	hat->name = hatname;
+	hat->parent = profile;
+
+	profile->null_profile = hat;
+
+	return 0;
+
+fail:
+	kfree(hatname);
+	free_aa_profile(hat);
+
+	return -ENOMEM;
+}
+
+/**
+ * alloc_null_complain_profile - Allocate the global null_complain_profile.
+ *
+ * Return %0 (success) or error (-%ENOMEM)
+ */
+int alloc_null_complain_profile(void)
+{
+	null_complain_profile = alloc_aa_profile();
+	if (!null_complain_profile)
+		goto fail;
+
+	null_complain_profile->name =
+		kstrdup("null-complain-profile", GFP_KERNEL);
+
+	if (!null_complain_profile->name)
+		goto fail;
+
+	null_complain_profile->flags.complain = 1;
+	if (attach_nullprofile(null_complain_profile))
+		goto fail;
+
+	return 0;
+
+fail:
+	/* free_aa_profile is safe for freeing partially constructed objects */
+	free_aa_profile(null_complain_profile);
+	null_complain_profile = NULL;
+
+	return -ENOMEM;
+}
+
+/**
+ * free_null_complain_profile - Free null profiles
+ */
+void free_null_complain_profile(void)
+{
+	aa_put_profile(null_complain_profile);
+	null_complain_profile = NULL;
+}
+
+/**
+ * aa_audit_message - Log a message to the audit subsystem
+ * @profile: profile to check against
+ * @gfp: allocation flags
+ * @flags: audit flags
+ * @fmt: varargs fmt
+ */
+int aa_audit_message(struct aa_profile *profile, gfp_t gfp, int flags,
+		     const char *fmt, ...)
+{
+	int ret;
+	struct aa_audit sa;
+
+	sa.type = AA_AUDITTYPE_MSG;
+	sa.name = fmt;
+	va_start(sa.vaval, fmt);
+	sa.flags = flags;
+	sa.gfp_mask = gfp;
+	sa.error_code = 0;
+	sa.result = 0;	/* fake failure: force message to be logged */
+
+	ret = aa_audit(profile, &sa);
+
+	va_end(sa.vaval);
+
+	return ret;
+}
+
+/**
+ * aa_audit_syscallreject - Log a syscall rejection to the audit subsystem
+ * @profile: profile to check against
+ * @msg: string describing syscall being rejected
+ * @gfp: memory allocation flags
+ */
+int aa_audit_syscallreject(struct aa_profile *profile, gfp_t gfp,
+			   const char *msg)
+{
+	struct aa_audit sa;
+
+	sa.type = AA_AUDITTYPE_SYSCALL;
+	sa.name = msg;
+	sa.flags = 0;
+	sa.gfp_mask = gfp;
+	sa.error_code = 0;
+	sa.result = 0; /* failure */
+
+	return aa_audit(profile, &sa);
+}
+
+/**
+ * aa_audit - Log an audit event to the audit subsystem
+ * @profile: profile to check against
+ * @sa: audit event
+ */
+int aa_audit(struct aa_profile *profile, const struct aa_audit *sa)
+{
+	struct audit_buffer *ab = NULL;
+	struct audit_context *audit_cxt;
+
+	const char *logcls;
+	unsigned int flags;
+	int audit = 0,
+	    complain = 0,
+	    error = -EINVAL,
+	    opspec_error = -EACCES;
+
+	const gfp_t gfp_mask = sa->gfp_mask;
+
+	WARN_ON(sa->type >= AA_AUDITTYPE__END);
+
+	/*
+	 * sa->result:	  1 success, 0 failure
+	 * sa->error_code: success: 0
+	 *		  failure: +ve mask of failed permissions or -ve
+	 *		  system error
+	 */
+
+	if (likely(sa->result)) {
+		if (likely(!PROFILE_AUDIT(profile))) {
+			/* nothing to log */
+			error = 0;
+			goto out;
+		} else {
+			audit = 1;
+			logcls = "AUDITING";
+		}
+	} else if (sa->error_code < 0) {
+		audit_log(current->audit_context, gfp_mask, AUDIT_APPARMOR,
+			"Internal error auditing event type %d (error %d)",
+			sa->type, sa->error_code);
+		AA_ERROR("Internal error auditing event type %d (error %d)\n",
+			sa->type, sa->error_code);
+		error = sa->error_code;
+		goto out;
+	} else if (sa->type == AA_AUDITTYPE_SYSCALL) {
+		/* Currently AA_AUDITTYPE_SYSCALL is for rejects only.
+		 * Values set by aa_audit_syscallreject will get us here.
+		 */
+		logcls = "REJECTING";
+	} else {
+		complain = PROFILE_COMPLAIN(profile);
+		logcls = complain ? "PERMITTING" : "REJECTING";
+	}
+
+	/* In future extend w/ per-profile flags
+	 * (flags |= sa->profile->flags)
+	 */
+	flags = sa->flags;
+	if (apparmor_logsyscall)
+		flags |= AA_AUDITFLAG_AUDITSS_SYSCALL;
+
+
+	/* Force full audit syscall logging regardless of global setting if
+	 * we are rejecting a syscall
+	 */
+	if (sa->type == AA_AUDITTYPE_SYSCALL) {
+		audit_cxt = current->audit_context;
+	} else {
+		audit_cxt = (flags & AA_AUDITFLAG_AUDITSS_SYSCALL) ?
+			current->audit_context : NULL;
+	}
+
+	ab = audit_log_start(audit_cxt, gfp_mask, AUDIT_APPARMOR);
+
+	if (!ab) {
+		AA_ERROR("Unable to log event (%d) to audit subsys\n",
+			sa->type);
+		if (complain)
+			error = 0;
+		goto out;
+	}
+
+	/* messages get special handling */
+	if (sa->type == AA_AUDITTYPE_MSG) {
+		audit_log_vformat(ab, sa->name, sa->vaval);
+		audit_log_end(ab);
+		error = 0;
+		goto out;
+	}
+
+	/* log operation */
+
+	audit_log_format(ab, "%s ", logcls);	/* REJECTING/ALLOWING/etc */
+
+	if (sa->type == AA_AUDITTYPE_FILE) {
+		int perm = audit ? sa->mask : sa->error_code;
+
+		audit_log_format(ab, "%s%s%s%s%s access to %s ",
+				 perm & AA_EXEC_MMAP ? "m" : "",
+				 perm & MAY_READ  ? "r" : "",
+				 perm & MAY_WRITE ? "w" : "",
+				 perm & MAY_EXEC  ? "x" : "",
+				 perm & AA_MAY_LINK  ? "l" : "",
+				 sa->name);
+
+		opspec_error = -EPERM;
+
+	} else if (sa->type == AA_AUDITTYPE_DIR) {
+		audit_log_format(ab, "%s on %s ", sa->operation, sa->name);
+
+	} else if (sa->type == AA_AUDITTYPE_ATTR) {
+		struct iattr *iattr = (struct iattr*)sa->pval;
+
+		audit_log_format(ab,
+			"attribute (%s%s%s%s%s%s%s) change to %s ",
+			iattr->ia_valid & ATTR_MODE ? "mode," : "",
+			iattr->ia_valid & ATTR_UID ? "uid," : "",
+			iattr->ia_valid & ATTR_GID ? "gid," : "",
+			iattr->ia_valid & ATTR_SIZE ? "size," : "",
+			((iattr->ia_valid & ATTR_ATIME_SET) ||
+			 (iattr->ia_valid & ATTR_ATIME)) ? "atime," : "",
+			((iattr->ia_valid & ATTR_MTIME_SET) ||
+			 (iattr->ia_valid & ATTR_MTIME)) ? "mtime," : "",
+			iattr->ia_valid & ATTR_CTIME ? "ctime," : "",
+			sa->name);
+
+	} else if (sa->type == AA_AUDITTYPE_XATTR) {
+		/* FIXME: how are special characters in sa->name escaped? */
+		/* FIXME: check if this can be handled on the stack
+			  with an inline varargs function. */
+		audit_log_format(ab, "%s on %s ", sa->operation, sa->name);
+
+	} else if (sa->type == AA_AUDITTYPE_LINK) {
+		audit_log_format(ab,
+			"link access from %s to %s ",
+			sa->name,
+			(char*)sa->pval);
+
+	} else if (sa->type == AA_AUDITTYPE_CAP) {
+		audit_log_format(ab,
+			"access to capability '%s' ",
+			capability_names[sa->capability]);
+
+		opspec_error = -EPERM;
+	} else if (sa->type == AA_AUDITTYPE_SYSCALL) {
+		audit_log_format(ab, "access to syscall '%s' ", sa->name);
+
+		opspec_error = -EPERM;
+	} else {
+		/* -EINVAL -- will WARN_ON above */
+		goto out;
+	}
+
+	audit_log_format(ab, "(%s(%d) profile %s active %s)",
+			 current->comm, current->pid,
+			 profile->parent->name, profile->name);
+
+	audit_log_end(ab);
+
+	if (complain)
+		error = 0;
+	else
+		error = sa->result ? 0 : opspec_error;
+
+out:
+	return error;
+}
+
+/**
+ * aa_attr - check if attribute change is allowed
+ * @profile: profile to check against
+ * @dentry: dentry of the file to check
+ * @mnt: vfsmount of the file to check
+ * @iattr: attribute changes requested
+ */
+int aa_attr(struct aa_profile *profile, struct dentry *dentry,
+	    struct vfsmount *mnt, struct iattr *iattr)
+{
+	struct inode *inode = dentry->d_inode;
+	int error, check;
+	struct aa_audit sa;
+
+	sa.type = AA_AUDITTYPE_ATTR;
+	sa.pval = iattr;
+	sa.flags = 0;
+	sa.gfp_mask = GFP_KERNEL;
+
+	check = 0;
+	if (inode && S_ISDIR(inode->i_mode))
+		check |= AA_CHECK_DIR;
+	if (iattr->ia_valid & ATTR_FILE)
+		check |= AA_CHECK_FD;
+
+	error = aa_perm_dentry(profile, dentry, mnt, &sa, MAY_WRITE, check);
+
+	return error;
+}
+
+/**
+ * aa_perm_xattr - check if xattr attribute change is allowed
+ * @profile: profile to check against
+ * @dentry: dentry of the file to check
+ * @mnt: vfsmount of the file to check
+ * @operation: xattr operation being done
+ * @xattr_name: name of xattr to check
+ * @mask: access mode requested
+ * @check: kind of check to perform
+ */
+int aa_perm_xattr(struct aa_profile *profile, struct dentry *dentry,
+		  struct vfsmount *mnt, const char *operation,
+		  const char *xattr_name, int mask, int check)
+{
+	struct inode *inode = dentry->d_inode;
+	int error;
+	struct aa_audit sa;
+
+	sa.type = AA_AUDITTYPE_XATTR;
+	sa.operation = operation;
+	sa.pval = xattr_name;
+	sa.flags = 0;
+	sa.gfp_mask = GFP_KERNEL;
+
+	if (inode && S_ISDIR(inode->i_mode))
+		check |= AA_CHECK_DIR;
+
+	error = aa_perm_dentry(profile, dentry, mnt, &sa, mask, check);
+
+	return error;
+}
+
+/**
+ * aa_perm - basic apparmor permissions check
+ * @profile: profile to check against
+ * @dentry: dentry of the file to check
+ * @mnt: vfsmount of the file to check
+ * @mask: access mode requested
+ * @check: kind of check to perform
+ *
+ * Determine if access @mask for the file is authorized by @profile.
+ * Returns 0 on success, or else an error code.
+ */
+int aa_perm(struct aa_profile *profile, struct dentry *dentry,
+	    struct vfsmount *mnt, int mask, int check)
+{
+	struct aa_audit sa;
+	int error = 0;
+
+	if ((check & (AA_CHECK_DIR | AA_CHECK_LEAF)) == AA_CHECK_DIR) {
+		/*
+		 * If checking a non-leaf directory, allow traverse and
+		 * write access: we do not require profile access to
+		 * non-leaf directories in order to traverse them,
+		 * create or remove files in them. We do require
+		 * MAY_WRITE profile access on the actual file or
+		 * directory being created or removed, though.
+		 */
+		mask &= ~(MAY_EXEC | MAY_WRITE);
+	}
+	if (mask == 0)
+		goto out;
+
+	sa.type = AA_AUDITTYPE_FILE;
+	sa.mask = mask;
+	sa.flags = 0;
+	sa.gfp_mask = GFP_KERNEL;
+	error = aa_perm_dentry(profile, dentry, mnt, &sa, mask, check);
+
+out:
+	return error;
+}
+
+/**
+ * aa_perm_dir
+ * @profile: profile to check against
+ * @dentry: dentry of directory to check
+ * @mnt: vfsmount of directory to check
+ * @operation: directory operation being performed
+ * @mask: access mode requested
+ *
+ * Determine if directory operation (make/remove) for dentry is authorized
+ * by @profile.
+ * Returns 0 on success, or else an error code.
+ */
+int aa_perm_dir(struct aa_profile *profile, struct dentry *dentry,
+		struct vfsmount *mnt, const char *operation, int mask)
+{
+	struct aa_audit sa;
+
+	sa.type = AA_AUDITTYPE_DIR;
+	sa.operation = operation;
+	sa.flags = 0;
+	sa.gfp_mask = GFP_KERNEL;
+
+	return aa_perm_dentry(profile, dentry, mnt, &sa, mask,
+			      AA_CHECK_DIR | AA_CHECK_LEAF);
+}
+
+/**
+ * aa_capability - test permission to use capability
+ * @cxt: aa_task_context with profile to check against
+ * @cap: capability to be tested
+ *
+ * Look up capability in profile capability set.
+ * Returns 0 on success, or else an error code.
+ */
+int aa_capability(struct aa_task_context *cxt, int cap)
+{
+	int error = cap_raised(cxt->profile->capabilities, cap) ? 0 : -EPERM;
+	struct aa_audit sa;
+
+	/* test if cap has alread been logged */
+	if (cap_raised(cxt->caps_logged, cap)) {
+		if (PROFILE_COMPLAIN(cxt->profile))
+			error = 0;
+		return error;
+	} else
+		/* don't worry about rcu replacement of the cxt here.
+		 * caps_logged is a cache to reduce the occurance of
+		 * duplicate messages in the log.  The worst that can
+		 * happen is duplicate capability messages shows up in
+		 * the audit log
+		 */
+		cap_raise(cxt->caps_logged, cap);
+
+	sa.type = AA_AUDITTYPE_CAP;
+	sa.name = NULL;
+	sa.capability = cap;
+	sa.flags = 0;
+	sa.error_code = 0;
+	sa.result = !error;
+	sa.gfp_mask = GFP_ATOMIC;
+
+	error = aa_audit(cxt->profile, &sa);
+
+	return error;
+}
+
+/* must be used inside rcu_read_lock or task_lock */
+int aa_may_ptrace(struct aa_task_context *cxt, struct aa_profile *tracee)
+{
+	if (!cxt || cxt->profile == tracee)
+		return 0;
+	return aa_capability(cxt, CAP_SYS_PTRACE);
+}
+
+/**
+ * aa_link - hard link check
+ * @profile: profile to check against
+ * @link: dentry of link being created
+ * @link_mnt: vfsmount of link being created
+ * @target: dentry of link target
+ * @target_mnt: vfsmunt of link target
+ *
+ * Returns 0 on success, or else an error code.
+ */
+int aa_link(struct aa_profile *profile,
+	    struct dentry *link, struct vfsmount *link_mnt,
+	    struct dentry *target, struct vfsmount *target_mnt)
+{
+	char *name_buffer = NULL, *pval_buffer = NULL;
+	int denied_mask = -EPERM, error;
+	struct aa_audit sa;
+
+	sa.name = aa_get_name(link, link_mnt, &name_buffer, 0);
+	sa.pval = aa_get_name(target, target_mnt, &pval_buffer, 0);
+
+	if (IS_ERR(sa.name)) {
+		denied_mask = PTR_ERR(sa.name);
+		sa.name = NULL;
+	}
+	if (IS_ERR(sa.pval)) {
+		denied_mask = PTR_ERR(sa.pval);
+		sa.pval = NULL;
+	}
+
+	if (sa.name && sa.pval)
+		denied_mask = aa_link_denied(profile, sa.name, sa.pval);
+
+	aa_permerror2result(denied_mask, &sa);
+
+	sa.type = AA_AUDITTYPE_LINK;
+	sa.flags = 0;
+	sa.gfp_mask = GFP_KERNEL;
+
+	error = aa_audit(profile, &sa);
+
+	aa_put_name_buffer(name_buffer);
+	aa_put_name_buffer(pval_buffer);
+
+	return error;
+}
+
+/*******************************
+ * Global task related functions
+ *******************************/
+
+/**
+ * aa_clone - initialize the task context for a new task
+ * @child: task that is being created
+ *
+ * Returns 0 on success, or else an error code.
+ */
+int aa_clone(struct task_struct *child)
+{
+	struct aa_task_context *cxt, *child_cxt;
+	struct aa_profile *profile;
+
+	if (!aa_task_context(current))
+		return 0;
+	child_cxt = aa_alloc_task_context(GFP_KERNEL);
+	if (!child_cxt)
+		return -ENOMEM;
+
+repeat:
+	profile = aa_get_profile(current);
+	if (profile) {
+		lock_profile(profile);
+		cxt = aa_task_context(current);
+		if (unlikely(profile->isstale || !cxt ||
+			     cxt->profile != profile)) {
+			/**
+			 * Race with profile replacement or removal, or with
+			 * task context removal.
+			 */
+			unlock_profile(profile);
+			aa_put_profile(profile);
+			goto repeat;
+		}
+
+		/* No need to grab the child's task lock here. */
+		aa_change_task_context(child, child_cxt, profile,
+				       cxt->hat_magic);
+		unlock_profile(profile);
+
+		if (APPARMOR_COMPLAIN(child_cxt) &&
+		    profile == null_complain_profile)
+			LOG_HINT(profile, GFP_KERNEL, HINT_FORK,
+				 "child=%d", child->pid);
+		aa_put_profile(profile);
+	} else
+		aa_free_task_context(child_cxt);
+
+	return 0;
+}
+
+static struct aa_profile *
+aa_register_find(struct aa_profile *profile, const char *name, int mandatory,
+		 int complain)
+{
+	struct aa_profile *new_profile;
+
+	/* Locate new profile */
+	new_profile = aa_find_profile(name);
+	if (new_profile) {
+		AA_DEBUG("%s: setting profile %s\n",
+			 __FUNCTION__, new_profile->name);
+	} else if (mandatory && profile) {
+		if (complain) {
+			LOG_HINT(profile, GFP_KERNEL, HINT_MANDPROF,
+				 "image '%s'", name);
+			profile = aa_dup_profile(null_complain_profile);
+		} else {
+			AA_REJECT_MSG(profile, GFP_KERNEL,
+				      "exec(2) of image '%s'. "
+				      "Profile mandatory and not found.",
+				      name);
+			return ERR_PTR(-EPERM);
+		}
+	} else {
+		/* Only way we can get into this code is if task
+		 * is unconfined.
+		 */
+		AA_DEBUG("%s: No profile found for exec image '%s'\n",
+			 __FUNCTION__,
+			 name);
+	}
+	return new_profile;
+}
+
+/**
+ * aa_register - register a new program
+ * @bprm: binprm of program being registered
+ *
+ * Try to register a new program during execve().  This should give the
+ * new program a valid aa_task_context if confined.
+ */
+int aa_register(struct linux_binprm *bprm)
+{
+	char *filename, *buffer = NULL;
+	struct file *filp = bprm->file;
+	struct aa_profile *profile, *old_profile, *new_profile = NULL;
+	int exec_mode = AA_EXEC_UNSAFE, complain = 0;
+
+	AA_DEBUG("%s\n", __FUNCTION__);
+
+	filename = aa_get_name(filp->f_dentry, filp->f_vfsmnt, &buffer, 0);
+	if (IS_ERR(filename)) {
+		AA_ERROR("%s: Failed to get filename", __FUNCTION__);
+		return -ENOENT;
+	}
+
+repeat:
+	profile = aa_get_profile(current);
+	if (profile) {
+		complain = PROFILE_COMPLAIN(profile);
+
+		/* Confined task, determine what mode inherit, unconfined or
+		 * mandatory to load new profile
+		 */
+		exec_mode = aa_match(profile->file_rules, filename);
+
+		if (exec_mode & (MAY_EXEC | AA_EXEC_MODIFIERS)) {
+			switch (exec_mode & (MAY_EXEC | AA_EXEC_MODIFIERS)) {
+			case MAY_EXEC | AA_EXEC_INHERIT:
+				AA_DEBUG("%s: INHERIT %s\n",
+					 __FUNCTION__,
+					 filename);
+				/* nothing to be done here */
+				goto cleanup;
+
+			case MAY_EXEC | AA_EXEC_UNCONFINED:
+				AA_DEBUG("%s: UNCONFINED %s\n",
+					 __FUNCTION__,
+					 filename);
+
+				/* detach current profile */
+				new_profile = NULL;
+				break;
+
+			case MAY_EXEC | AA_EXEC_PROFILE:
+				AA_DEBUG("%s: PROFILE %s\n",
+					 __FUNCTION__,
+					 filename);
+				new_profile = aa_register_find(profile,
+							       filename, 1,
+							       complain);
+				break;
+
+			default:
+				AA_ERROR("Rejecting exec(2) of image '%s'. "
+					 "Unknown exec qualifier %x "
+					 "(%s (pid %d) profile %s active %s)\n",
+					 filename,
+					 exec_mode & AA_EXEC_MODIFIERS,
+					 current->comm, current->pid,
+					 profile->parent->name,
+					 profile->name);
+				new_profile = ERR_PTR(-EPERM);
+				break;
+			}
+
+		} else if (complain) {
+			/* There was no entry in calling profile
+			 * describing mode to execute image in.
+			 * Drop into null-profile (disabling secure exec).
+			 */
+			new_profile = aa_dup_profile(null_complain_profile);
+			exec_mode |= AA_EXEC_UNSAFE;
+		} else {
+			AA_REJECT_MSG(profile, GFP_KERNEL,
+				      "exec(2) of image '%s'. "
+				      "Unable to determine exec qualifier.",
+				      filename);
+			new_profile = ERR_PTR(-EPERM);
+		}
+	} else {
+		/* Unconfined task, load profile if it exists */
+		new_profile = aa_register_find(NULL, filename, 0, 0);
+		if (new_profile == NULL)
+			goto cleanup;
+	}
+
+	if (IS_ERR(new_profile))
+		goto cleanup;
+
+	old_profile = __aa_replace_profile(current, new_profile, 0);
+	if (IS_ERR(old_profile)) {
+		aa_put_profile(new_profile);
+		aa_put_profile(profile);
+		if (PTR_ERR(old_profile) == -ESTALE)
+			goto repeat;
+		if (PTR_ERR(old_profile) == -EPERM)
+			AA_REJECT_MSG(profile, GFP_KERNEL,
+				"exec(2) of image '%s'. "
+				"Unable to change profile, ptraced by %d.",
+				filename, current->parent->pid);
+		new_profile = old_profile;
+		goto cleanup;
+	}
+	aa_put_profile(old_profile);
+	aa_put_profile(profile);
+
+	/* Handle confined exec.
+	 * Can be at this point for the following reasons:
+	 * 1. unconfined switching to confined
+	 * 2. confined switching to different confinement
+	 * 3. confined switching to unconfined
+	 *
+	 * Cases 2 and 3 are marked as requiring secure exec
+	 * (unless policy specified "unsafe exec")
+	 */
+	if (!(exec_mode & AA_EXEC_UNSAFE)) {
+		unsigned long bprm_flags;
+
+		bprm_flags = AA_SECURE_EXEC_NEEDED;
+		bprm->security = (void*)
+			((unsigned long)bprm->security | bprm_flags);
+	}
+
+	if (complain && new_profile == null_complain_profile)
+		LOG_HINT(new_profile, GFP_ATOMIC, HINT_CHGPROF,
+			 "");
+
+cleanup:
+	aa_put_name_buffer(buffer);
+	if (IS_ERR(new_profile))
+		return PTR_ERR(new_profile);
+	aa_put_profile(new_profile);
+	return 0;
+}
+
+/**
+ * aa_release - release a task context
+ * @task: task being released
+ *
+ * This is called after a task has exited and the parent has reaped it.
+ */
+void aa_release(struct task_struct *task)
+{
+	struct aa_task_context *cxt;
+	struct aa_profile *profile;
+	/*
+	 * While the task context is still on a profile's task context
+	 * list, another process could replace the profile under us,
+	 * leaving us with a locked profile that is no longer attached
+	 * to this task. So after locking the profile, we check that
+	 * the profile is still attached.  The profile lock is
+	 * sufficient to prevent the replacement race so we do not lock
+	 * the task.
+	 *
+	 * lock_dep reports a false 'possible irq lock inversion dependency'
+	 * between the profile lock and the task_lock.
+	 *
+	 * We also avoid taking the task_lock here because lock_dep
+	 * would report another false {softirq-on-W} potential irq_lock
+	 * inversion.
+	 *
+	 * If the task does not have a profile attached we are safe;
+	 * nothing can race with us at this point.
+	 */
+
+repeat:
+	profile = aa_get_profile(task);
+	if (profile) {
+		lock_profile(profile);
+		cxt = aa_task_context(task);
+		if (unlikely(!cxt || cxt->profile != profile)) {
+			unlock_profile(profile);
+			aa_put_profile(profile);
+			goto repeat;
+		}
+		aa_change_task_context(task, NULL, NULL, 0);
+		unlock_profile(profile);
+		aa_put_profile(profile);
+	}
+}
+
+/**
+ * do_change_hat - actually switch hats
+ * @hat_name: name of hat to switch to
+ * @new_cxt: new aa_task_context to use on profile change
+ * @hat_magic: new magic value to use
+ *
+ * Switch to a new hat.  Returns %0 on success, error otherwise.
+ */
+static int do_change_hat(const char *hat_name,
+			 struct aa_task_context *new_cxt, u64 hat_magic)
+{
+	struct aa_task_context *cxt = aa_task_context(current);
+	struct aa_profile *sub;
+	int error = 0;
+
+	/*
+	 * Note: the profile and sub-profiles cannot go away under us here;
+	 * no need to grab an additional reference count.
+	 */
+	sub = __aa_find_profile(hat_name, &cxt->profile->parent->sub);
+
+	if ((current->ptrace & PT_PTRACED) && aa_may_ptrace(cxt, sub))
+		return -EPERM;
+
+	if (sub) {
+		/* change hat */
+		aa_change_task_context(current, new_cxt, sub, hat_magic);
+	} else {
+		struct aa_profile *profile = cxt->profile;
+
+		if (APPARMOR_COMPLAIN(cxt)) {
+			LOG_HINT(profile, GFP_ATOMIC, HINT_UNKNOWN_HAT,
+				 "%s", hat_name);
+		} else {
+			AA_DEBUG("%s: Unknown hatname '%s'. "
+				"Changing to NULL profile "
+				"(%s(%d) profile %s active %s)\n",
+				 __FUNCTION__,
+				 hat_name,
+				 current->comm, current->pid,
+				 profile->parent->name,
+				 profile->name);
+			error = -EACCES;
+		}
+		/*
+		 * Switch to the NULL profile: it grants no accesses, so in
+		 * learning mode all accesses will get logged, and in enforce
+		 * mode all accesses will be denied.
+		 *
+		 * In learning mode, this allows us to learn about new hats.
+		 */
+		aa_change_task_context(current, new_cxt,
+				       cxt->profile->null_profile, hat_magic);
+	}
+
+	return error;
+}
+
+/**
+ * aa_change_hat - change hat to/from subprofile
+ * @hat_name: hat to change to
+ * @hat_magic: magic cookie to validate the hat change
+ *
+ * Change to new @hat_name, and store the @hat_magic in the current task
+ * context.  If the new @hat_name is %NULL and the @hat_magic matches that
+ * stored in the current task context and is not 0, return to the top level
+ * profile.
+ * Returns %0 on success, error otherwise.
+ */
+int aa_change_hat(const char *hat_name, u64 hat_magic)
+{
+	struct aa_task_context *cxt, *new_cxt;
+	struct aa_profile *profile = NULL;
+	int error = 0;
+
+	/* Dump out above debugging in WARN mode if we are in AUDIT mode */
+	if (APPARMOR_AUDIT(aa_task_context(current))) {
+		AA_WARN(GFP_KERNEL, "change_hat %s, 0x%llx (pid %d)",
+			hat_name ? hat_name : "NULL",
+			hat_magic, current->pid);
+	}
+
+	new_cxt = aa_alloc_task_context(GFP_KERNEL);
+	if (!new_cxt)
+		return -ENOMEM;
+
+	cxt = lock_task_and_profiles(current, NULL);
+	if (!cxt) {
+		/* An unconfined process cannot change_hat(). */
+		error = -EPERM;
+		goto out;
+	}
+
+	/* No need to get reference count: we do not sleep. */
+	profile = cxt->profile;
+
+	/* check to see if the confined process has any hats. */
+	if (list_empty(&profile->parent->sub) && !PROFILE_COMPLAIN(profile)) {
+		error = -ECHILD;
+		goto out;
+	}
+
+	if (profile == profile->parent) {
+		/* We are in the parent profile. */
+		if (hat_name) {
+			AA_DEBUG("%s: switching to %s, 0x%llx\n",
+				 __FUNCTION__,
+				 hat_name,
+				 hat_magic);
+			error = do_change_hat(hat_name, new_cxt, hat_magic);
+		}
+	} else {
+		/*
+		 * We are in a child profile.
+		 *
+		 * Check to make sure magic is same as what was passed when
+		 * we switched into this profile.  Handle special casing of
+		 * NULL magic which confines task to subprofile and prohibits
+		 * further change_hats.
+		 */
+		if (hat_magic && hat_magic == cxt->hat_magic) {
+			if (!hat_name) {
+				/* Return from subprofile back to parent. */
+				aa_change_task_context(current, new_cxt,
+						       profile->parent, 0);
+			} else {
+				/*
+				 * Change to another (sibling) profile, and
+				 * stick with the same hat_magic.
+				 */
+				error = do_change_hat(hat_name, new_cxt,
+						      cxt->hat_magic);
+			}
+		} else if (cxt->hat_magic) {
+			AA_ERROR("KILLING process %s(%d) "
+				 "Invalid change_hat() magic# 0x%llx "
+				 "(hatname %s profile %s active %s)\n",
+				 current->comm, current->pid,
+				 hat_magic,
+				 hat_name ? hat_name : "NULL",
+				 profile->parent->name,
+				 profile->name);
+
+			/* terminate current process */
+			(void)send_sig_info(SIGKILL, NULL, current);
+		} else {	/* cxt->hat_magic == 0 */
+			AA_ERROR("KILLING process %s(%d) "
+				 "Task was confined to current subprofile "
+				 "(profile %s active %s)\n",
+				 current->comm, current->pid,
+				 profile->parent->name,
+				 profile->name);
+
+			/* terminate current process */
+			(void)send_sig_info(SIGKILL, NULL, current);
+		}
+
+	}
+
+out:
+	if (aa_task_context(current) != new_cxt)
+		aa_free_task_context(new_cxt);
+	task_unlock(current);
+	unlock_profile(profile);
+	return error;
+}
+
+/**
+ * __aa_replace_profile - replace a task's profile
+ * @task: task to switch the profile of
+ * @profile: profile to switch to
+ * @hat_magic: magic cookie to switch to
+ *
+ * Returns a handle to the previous profile upon success, or else an
+ * error code.
+ */
+struct aa_profile *__aa_replace_profile(struct task_struct *task,
+					struct aa_profile *profile,
+					u32 hat_magic)
+{
+	struct aa_task_context *cxt, *new_cxt = NULL;
+	struct aa_profile *old_profile = NULL;
+
+	if (profile) {
+		new_cxt = aa_alloc_task_context(GFP_KERNEL);
+		if (!new_cxt)
+			return ERR_PTR(-ENOMEM);
+	}
+
+	cxt = lock_task_and_profiles(task, profile);
+	if (unlikely(profile && profile->isstale)) {
+		task_unlock(task);
+		unlock_both_profiles(profile, cxt ? cxt->profile : NULL);
+		aa_free_task_context(new_cxt);
+		return ERR_PTR(-ESTALE);
+	}
+
+	if ((current->ptrace & PT_PTRACED) && aa_may_ptrace(cxt, profile)) {
+		task_unlock(task);
+		unlock_both_profiles(profile, cxt ? cxt->profile : NULL);
+		aa_free_task_context(new_cxt);
+		return ERR_PTR(-EPERM);
+	}
+
+	if (cxt) {
+		old_profile = aa_dup_profile(cxt->profile);
+		aa_change_task_context(task, new_cxt, profile, cxt->hat_magic);
+	} else
+		aa_change_task_context(task, new_cxt, profile, 0);
+
+	task_unlock(task);
+	unlock_both_profiles(profile, old_profile);
+	return old_profile;
+}
+
+/**
+ * lock_task_and_profile - lock the task and confining profiles and @profile
+ * @task - task to lock
+ * @profile - extra profile to lock in addition to the current profile
+ *
+ * Handle the spinning on locking to make sure the task context and
+ * profile are consistent once all locks are aquired.
+ *
+ * return the aa_task_context currently confining the task.  The task lock
+ * will be held whether or not the task is confined.
+ */
+struct aa_task_context *
+lock_task_and_profiles(struct task_struct *task, struct aa_profile *profile)
+{
+	struct aa_task_context *cxt;
+	struct aa_profile *old_profile = NULL;
+
+	rcu_read_lock();
+repeat:
+	cxt = aa_task_context(task);
+	if (cxt)
+		old_profile = cxt->profile;
+	lock_both_profiles(profile, old_profile);
+	task_lock(task);
+
+	/* check for race with profile transition, replacement or removal */
+	if (unlikely(cxt != aa_task_context(task))) {
+		task_unlock(task);
+		unlock_both_profiles(profile, old_profile);
+		goto repeat;
+	}
+	rcu_read_unlock();
+	return cxt;
+}
+
+static void free_aa_task_context_rcu_callback(struct rcu_head *head)
+{
+	struct aa_task_context *cxt;
+
+	cxt = container_of(head, struct aa_task_context, rcu);
+	aa_free_task_context(cxt);
+}
+
+/**
+ * aa_change_task_context - switch a task to use a new context and profile
+ * @task: task that is having its task context changed
+ * @new_cxt: new task context to use after the switch
+ * @profile: new profile to use after the switch
+ * @hat_magic: hat value to switch to (0 for no hat)
+ */
+void aa_change_task_context(struct task_struct *task,
+			    struct aa_task_context *new_cxt,
+			    struct aa_profile *profile, u64 hat_magic)
+{
+	struct aa_task_context *old_cxt = aa_task_context(task);
+
+	if (old_cxt) {
+		list_del_init(&old_cxt->list);
+		call_rcu(&old_cxt->rcu, free_aa_task_context_rcu_callback);
+	}
+	if (new_cxt) {
+		/* clear the caps_logged cache, so that new profile/hat has
+		 * chance to emit its own set of cap messages */
+		new_cxt->caps_logged = CAP_EMPTY_SET;
+		new_cxt->hat_magic = hat_magic;
+		new_cxt->task = task;
+		new_cxt->profile = aa_dup_profile(profile);
+		list_move(&new_cxt->list, &profile->parent->task_contexts);
+	}
+	rcu_assign_pointer(task->security, new_cxt);
+}

-- 

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

* [AppArmor 38/41] AppArmor: Module and LSM hooks
  2007-04-12  9:08 [AppArmor 00/41] AppArmor security module overview jjohansen
                   ` (36 preceding siblings ...)
  2007-04-12  9:08 ` [AppArmor 37/41] AppArmor: Main Part jjohansen
@ 2007-04-12  9:08 ` jjohansen
  2007-04-12 10:21   ` Alan Cox
  2007-04-12  9:08 ` [AppArmor 39/41] AppArmor: Profile loading and manipulation, pathname matching jjohansen
                   ` (5 subsequent siblings)
  43 siblings, 1 reply; 187+ messages in thread
From: jjohansen @ 2007-04-12  9:08 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, linux-fsdevel, chrisw, John Johansen,
	Andreas Gruenbacher

[-- Attachment #1: apparmor-lsm.diff --]
[-- Type: text/plain, Size: 21771 bytes --]

Module parameters, LSM hooks, initialization and teardown.

Signed-off-by: John Johansen <jjohansen@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>

---
 security/apparmor/lsm.c |  829 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 829 insertions(+)

--- /dev/null
+++ b/security/apparmor/lsm.c
@@ -0,0 +1,829 @@
+/*
+ *	Copyright (C) 1998-2007 Novell/SUSE
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License as
+ *	published by the Free Software Foundation, version 2 of the
+ *	License.
+ *
+ *	AppArmor LSM interface
+ */
+
+#include <linux/security.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/mount.h>
+#include <linux/namei.h>
+#include <linux/ctype.h>
+
+#include "apparmor.h"
+#include "inline.h"
+
+static int param_set_aabool(const char *val, struct kernel_param *kp);
+static int param_get_aabool(char *buffer, struct kernel_param *kp);
+#define param_check_aabool(name, p) __param_check(name, p, int)
+
+static int param_set_aauint(const char *val, struct kernel_param *kp);
+static int param_get_aauint(char *buffer, struct kernel_param *kp);
+#define param_check_aauint(name, p) __param_check(name, p, int)
+
+/* Flag values, also controllable via /sys/module/apparmor/parameters
+ * We define special types as we want to do additional mediation.
+ *
+ * Complain mode -- in complain mode access failures result in auditing only
+ * and task is allowed access.  audit events are processed by userspace to
+ * generate policy.  Default is 'enforce' (0).
+ * Value is also togglable per profile and referenced when global value is
+ * enforce.
+ */
+int apparmor_complain = 0;
+module_param_named(complain, apparmor_complain, aabool, S_IRUSR | S_IWUSR);
+MODULE_PARM_DESC(apparmor_complain, "Toggle AppArmor complain mode");
+
+/* Debug mode */
+int apparmor_debug = 0;
+module_param_named(debug, apparmor_debug, aabool, S_IRUSR | S_IWUSR);
+MODULE_PARM_DESC(apparmor_debug, "Toggle AppArmor debug mode");
+
+/* Audit mode */
+int apparmor_audit = 0;
+module_param_named(audit, apparmor_audit, aabool, S_IRUSR | S_IWUSR);
+MODULE_PARM_DESC(apparmor_audit, "Toggle AppArmor audit mode");
+
+/* Syscall logging mode */
+int apparmor_logsyscall = 0;
+module_param_named(logsyscall, apparmor_logsyscall, aabool, S_IRUSR | S_IWUSR);
+MODULE_PARM_DESC(apparmor_logsyscall, "Toggle AppArmor logsyscall mode");
+
+/* Maximum pathname length before accesses will start getting rejected */
+unsigned int apparmor_path_max = 2 * PATH_MAX;
+module_param_named(path_max, apparmor_path_max, aauint, S_IRUSR | S_IWUSR);
+MODULE_PARM_DESC(apparmor_path_max, "Maximum pathname length allowed");
+
+static int param_set_aabool(const char *val, struct kernel_param *kp)
+{
+	if (aa_task_context(current))
+		return -EPERM;
+	return param_set_bool(val, kp);
+}
+
+static int param_get_aabool(char *buffer, struct kernel_param *kp)
+{
+	if (aa_task_context(current))
+		return -EPERM;
+	return param_get_bool(buffer, kp);
+}
+
+static int param_set_aauint(const char *val, struct kernel_param *kp)
+{
+	if (aa_task_context(current))
+		return -EPERM;
+	return param_set_uint(val, kp);
+}
+
+static int param_get_aauint(char *buffer, struct kernel_param *kp)
+{
+	if (aa_task_context(current))
+		return -EPERM;
+	return param_get_uint(buffer, kp);
+}
+
+static int aa_reject_syscall(struct task_struct *task, gfp_t flags,
+			     const char *name)
+{
+	struct aa_profile *profile = aa_get_profile(task);
+	int error = 0;
+
+	if (profile) {
+		error = aa_audit_syscallreject(profile, flags, name);
+		aa_put_profile(profile);
+	}
+
+	return error;
+}
+
+static int apparmor_ptrace(struct task_struct *parent,
+			   struct task_struct *child)
+{
+	struct aa_task_context *cxt;
+	struct aa_task_context *child_cxt;
+	struct aa_profile *child_profile;
+	int error = 0;
+
+	/**
+	 * parent can ptrace child when
+	 * - parent is unconfined
+	 * - parent is in complain mode
+	 * - parent and child are confined by the same profile
+	 */
+
+	rcu_read_lock();
+	cxt = aa_task_context(parent);
+	child_cxt = aa_task_context(child);
+	child_profile = child_cxt ? child_cxt->profile : NULL;
+	error = aa_may_ptrace(cxt, child_profile);
+	if (cxt && PROFILE_COMPLAIN(cxt->profile)) {
+		LOG_HINT(cxt->profile, GFP_ATOMIC, HINT_PTRACE,
+				 "pid=%d child=%d\n",
+				 current->pid, child->pid);
+		}
+	rcu_read_unlock();
+
+	return error;
+}
+
+static int apparmor_capget(struct task_struct *task,
+			    kernel_cap_t *effective,
+			    kernel_cap_t *inheritable,
+			    kernel_cap_t *permitted)
+{
+	return cap_capget(task, effective, inheritable, permitted);
+}
+
+static int apparmor_capset_check(struct task_struct *task,
+				  kernel_cap_t *effective,
+				  kernel_cap_t *inheritable,
+				  kernel_cap_t *permitted)
+{
+	return cap_capset_check(task, effective, inheritable, permitted);
+}
+
+static void apparmor_capset_set(struct task_struct *task,
+				 kernel_cap_t *effective,
+				 kernel_cap_t *inheritable,
+				 kernel_cap_t *permitted)
+{
+	cap_capset_set(task, effective, inheritable, permitted);
+}
+
+static int apparmor_capable(struct task_struct *task, int cap)
+{
+	int error;
+
+	/* cap_capable returns 0 on success, else -EPERM */
+	error = cap_capable(task, cap);
+
+	if (!error) {
+		struct aa_task_context *cxt;
+
+		rcu_read_lock();
+		cxt = aa_task_context(task);
+		if (cxt)
+			error = aa_capability(cxt, cap);
+		rcu_read_unlock();
+	}
+
+	return error;
+}
+
+static int apparmor_sysctl(struct ctl_table *table, int op)
+{
+	int error = 0;
+
+	if ((op & 002) && !capable(CAP_SYS_ADMIN))
+		error = aa_reject_syscall(current, GFP_KERNEL,
+					  "sysctl (write)");
+
+	return error;
+}
+
+static int apparmor_syslog(int type)
+{
+	return cap_syslog(type);
+}
+
+static int apparmor_netlink_send(struct sock *sk, struct sk_buff *skb)
+{
+	return cap_netlink_send(sk, skb);
+}
+
+static int apparmor_netlink_recv(struct sk_buff *skb, int cap)
+{
+	return cap_netlink_recv(skb, cap);
+}
+
+static void apparmor_bprm_apply_creds(struct linux_binprm *bprm, int unsafe)
+{
+	cap_bprm_apply_creds(bprm, unsafe);
+}
+
+static int apparmor_bprm_set_security(struct linux_binprm *bprm)
+{
+	/* handle capability bits with setuid, etc */
+	cap_bprm_set_security(bprm);
+	/* already set based on script name */
+	if (bprm->sh_bang)
+		return 0;
+	return aa_register(bprm);
+}
+
+static int apparmor_bprm_secureexec(struct linux_binprm *bprm)
+{
+	int ret = cap_bprm_secureexec(bprm);
+
+	if (!ret && (unsigned long)bprm->security & AA_SECURE_EXEC_NEEDED) {
+		AA_DEBUG("%s: secureexec required for %s\n",
+			 __FUNCTION__, bprm->filename);
+		ret = 1;
+	}
+
+	return ret;
+}
+
+static int apparmor_sb_mount(char *dev_name, struct nameidata *nd, char *type,
+			      unsigned long flags, void *data)
+{
+	return aa_reject_syscall(current, GFP_KERNEL, "mount");
+}
+
+static int apparmor_umount(struct vfsmount *mnt, int flags)
+{
+	return aa_reject_syscall(current, GFP_KERNEL, "umount");
+}
+
+static int apparmor_inode_mkdir(struct inode *dir, struct dentry *dentry,
+				struct vfsmount *mnt, int mask)
+{
+	struct aa_profile *profile;
+	int error = 0;
+
+	if (!mnt || !mediated_filesystem(dir))
+		goto out;
+
+	profile = aa_get_profile(current);
+
+	if (profile)
+		error = aa_perm_dir(profile, dentry, mnt, "mkdir", MAY_WRITE);
+
+	aa_put_profile(profile);
+
+out:
+	return error;
+}
+
+static int apparmor_inode_rmdir(struct inode *dir, struct dentry *dentry,
+				struct vfsmount *mnt)
+{
+	struct aa_profile *profile;
+	int error = 0;
+
+	if (!mnt || !mediated_filesystem(dir))
+		goto out;
+
+	profile = aa_get_profile(current);
+
+	if (profile)
+		error = aa_perm_dir(profile, dentry, mnt, "rmdir", MAY_WRITE);
+
+	aa_put_profile(profile);
+
+out:
+	return error;
+}
+
+static int aa_permission(struct inode *inode, struct dentry *dentry,
+			 struct vfsmount *mnt, int mask, int check)
+{
+	int error = 0;
+
+	if (mnt && mediated_filesystem(inode)) {
+		struct aa_profile *profile;
+
+		profile = aa_get_profile(current);
+		if (profile)
+			error = aa_perm(profile, dentry, mnt, mask, check);
+		aa_put_profile(profile);
+	}
+	return error;
+}
+
+static int apparmor_inode_create(struct inode *dir, struct dentry *dentry,
+				 struct vfsmount *mnt, int mask)
+{
+	return aa_permission(dir, dentry, mnt, MAY_WRITE, AA_CHECK_LEAF);
+}
+
+static int apparmor_inode_link(struct dentry *old_dentry,
+			       struct vfsmount *old_mnt, struct inode *dir,
+			       struct dentry *new_dentry,
+			       struct vfsmount *new_mnt)
+{
+	int error = 0;
+	struct aa_profile *profile;
+
+	if (!old_mnt || !new_mnt || !mediated_filesystem(dir))
+		goto out;
+
+	profile = aa_get_profile(current);
+
+	if (profile)
+		error = aa_link(profile, new_dentry, new_mnt,
+				old_dentry, old_mnt);
+
+	aa_put_profile(profile);
+
+out:
+	return error;
+}
+
+static int apparmor_inode_unlink(struct inode *dir, struct dentry *dentry,
+				 struct vfsmount *mnt)
+{
+	int check = AA_CHECK_LEAF;
+
+	if (S_ISDIR(dentry->d_inode->i_mode))
+		check |= AA_CHECK_DIR;
+	return aa_permission(dir, dentry, mnt, MAY_WRITE, check);
+}
+
+static int apparmor_inode_symlink(struct inode *dir, struct dentry *dentry,
+				  struct vfsmount *mnt, const char *old_name)
+{
+	return aa_permission(dir, dentry, mnt, MAY_WRITE, AA_CHECK_LEAF);
+}
+
+static int apparmor_inode_mknod(struct inode *dir, struct dentry *dentry,
+				struct vfsmount *mnt, int mode, dev_t dev)
+{
+	return aa_permission(dir, dentry, mnt, MAY_WRITE, AA_CHECK_LEAF);
+}
+
+static int apparmor_inode_rename(struct inode *old_dir,
+				 struct dentry *old_dentry,
+				 struct vfsmount *old_mnt,
+				 struct inode *new_dir,
+				 struct dentry *new_dentry,
+				 struct vfsmount *new_mnt)
+{
+	struct aa_profile *profile;
+	int error = 0;
+
+	if ((!old_mnt && !new_mnt) || !mediated_filesystem(old_dir))
+		goto out;
+
+	profile = aa_get_profile(current);
+
+	if (profile) {
+		struct inode *inode = old_dentry->d_inode;
+		int check = AA_CHECK_LEAF;
+
+		if (inode && S_ISDIR(inode->i_mode))
+			check |= AA_CHECK_DIR;
+		if (old_mnt)
+			error = aa_perm(profile, old_dentry, old_mnt,
+					MAY_READ | MAY_WRITE, check);
+
+		if (!error && new_mnt) {
+			error = aa_perm(profile, new_dentry, new_mnt,
+					MAY_WRITE, check);
+		}
+	}
+
+	aa_put_profile(profile);
+
+out:
+	return error;
+}
+
+static int apparmor_inode_permission(struct inode *inode, int mask,
+				     struct nameidata *nd)
+{
+	int check = 0;
+
+	if (!nd)
+		return 0;
+	if (S_ISDIR(inode->i_mode))
+		check |= AA_CHECK_DIR;
+	mask &= (MAY_READ | MAY_WRITE | MAY_EXEC);
+
+	/* Assume we are not checking a leaf directory. */
+	return aa_permission(inode, nd->dentry, nd->mnt, mask, check);
+}
+
+static int apparmor_inode_setattr(struct dentry *dentry, struct vfsmount *mnt,
+				  struct iattr *iattr)
+{
+	int error = 0;
+
+	if (!mnt)
+		goto out;
+
+	if (mediated_filesystem(dentry->d_inode)) {
+		struct aa_profile *profile;
+
+		profile = aa_get_profile(current);
+		/*
+		 * Mediate any attempt to change attributes of a file
+		 * (chmod, chown, chgrp, etc)
+		 */
+		if (profile)
+			error = aa_attr(profile, dentry, mnt, iattr);
+
+		aa_put_profile(profile);
+	}
+
+out:
+	return error;
+}
+
+static int aa_xattr_permission(struct dentry *dentry, struct vfsmount *mnt,
+			       const char *name, const char *operation,
+			       int mask, struct file *file)
+{
+	int error = 0;
+
+	if (mnt && mediated_filesystem(dentry->d_inode)) {
+		struct aa_profile *profile = aa_get_profile(current);
+		int check = file ? AA_CHECK_FD : 0;
+
+		if (profile)
+			error = aa_perm_xattr(profile, dentry, mnt, name,
+					      operation, mask, check);
+		aa_put_profile(profile);
+	}
+
+	return error;
+}
+
+static int apparmor_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt,
+				   char *name, void *value, size_t size,
+				   int flags, struct file *file)
+{
+	return aa_xattr_permission(dentry, mnt, name, "xattr set", MAY_WRITE,
+				   file);
+}
+
+static int apparmor_inode_getxattr(struct dentry *dentry, struct vfsmount *mnt,
+				   char *name, struct file *file)
+{
+	return aa_xattr_permission(dentry, mnt, name, "xattr get", MAY_READ,
+				   file);
+}
+
+static int apparmor_inode_listxattr(struct dentry *dentry, struct vfsmount *mnt,
+				    struct file *file)
+{
+	return aa_xattr_permission(dentry, mnt, NULL, "xattr list", MAY_READ,
+				   file);
+}
+
+static int apparmor_inode_removexattr(struct dentry *dentry,
+				      struct vfsmount *mnt, char *name,
+				      struct file *file)
+{
+	return aa_xattr_permission(dentry, mnt, name, "xattr remove",
+				   MAY_WRITE, file);
+}
+
+static int apparmor_file_permission(struct file *file, int mask)
+{
+	struct aa_profile *profile;
+	struct aa_profile *file_profile = (struct aa_profile*)file->f_security;
+	int error = 0;
+
+	if (!file_profile)
+		goto out;
+
+	/*
+	 * If this file was opened under a different profile, we
+	 * revalidate the access against the current profile.
+	 */
+	profile = aa_get_profile(current);
+	if (profile && file_profile != profile) {
+		struct dentry *dentry = file->f_dentry;
+		struct vfsmount *mnt = file->f_vfsmnt;
+		struct inode *inode = dentry->d_inode;
+		int check = AA_CHECK_LEAF | AA_CHECK_FD;
+
+		/*
+		 * FIXME: We should remember which profiles we revalidated
+		 *	  against.
+		 */
+		if (S_ISDIR(inode->i_mode))
+			check |= AA_CHECK_DIR;
+		mask &= (MAY_READ | MAY_WRITE | MAY_EXEC);
+		error = aa_permission(inode, dentry, mnt, mask, check);
+	}
+	aa_put_profile(profile);
+
+out:
+	return error;
+}
+
+static int apparmor_task_create(unsigned long clone_flags)
+{
+	struct aa_profile *profile;
+	int error = 0;
+
+	profile = aa_get_profile(current);
+	if (profile) {
+		/* Don't allow to create new namespaces. */
+		if (clone_flags & CLONE_NEWNS)
+			error = -EPERM;
+	}
+	aa_put_profile(profile);
+
+	return error;
+}
+
+static int apparmor_file_alloc_security(struct file *file)
+{
+	struct aa_profile *profile;
+
+	profile = aa_get_profile(current);
+	if (profile)
+		file->f_security = profile;
+
+	return 0;
+}
+
+static void apparmor_file_free_security(struct file *file)
+{
+	struct aa_profile *file_profile = (struct aa_profile*)file->f_security;
+
+	aa_put_profile(file_profile);
+}
+
+static inline int aa_mmap(struct file *file, unsigned long prot,
+			  unsigned long flags)
+{
+	struct dentry *dentry;
+	int mask = 0;
+
+	if (!file || !file->f_security)
+		return 0;
+
+	if (prot & PROT_READ)
+		mask |= MAY_READ;
+	/* Private mappings don't require write perms since they don't
+	 * write back to the files */
+	if ((prot & PROT_WRITE) && !(flags & MAP_PRIVATE))
+		mask |= MAY_WRITE;
+	if (prot & PROT_EXEC)
+		mask |= AA_EXEC_MMAP;
+
+	dentry = file->f_dentry;
+	return aa_permission(dentry->d_inode, dentry, file->f_vfsmnt, mask,
+			     AA_CHECK_LEAF | AA_CHECK_FD);
+}
+
+static int apparmor_file_mmap(struct file *file, unsigned long reqprot,
+			       unsigned long prot, unsigned long flags)
+{
+	return aa_mmap(file, prot, flags);
+}
+
+static int apparmor_file_mprotect(struct vm_area_struct *vma,
+				  unsigned long reqprot, unsigned long prot)
+{
+	return aa_mmap(vma->vm_file, prot,
+		       !(vma->vm_flags & VM_SHARED) ? MAP_PRIVATE : 0);
+}
+
+static int apparmor_task_alloc_security(struct task_struct *task)
+{
+	return aa_clone(task);
+}
+
+/*
+ * Called from IRQ context from RCU callback.
+ */
+static void apparmor_task_free_security(struct task_struct *task)
+{
+	aa_release(task);
+}
+
+static int apparmor_task_post_setuid(uid_t id0, uid_t id1, uid_t id2,
+				     int flags)
+{
+	return cap_task_post_setuid(id0, id1, id2, flags);
+}
+
+static void apparmor_task_reparent_to_init(struct task_struct *task)
+{
+	cap_task_reparent_to_init(task);
+}
+
+static int apparmor_getprocattr(struct task_struct *task, char *name,
+				char **value)
+{
+	unsigned len;
+	int error;
+	struct aa_profile *profile;
+
+	/* AppArmor only supports the "current" process attribute */
+	if (strcmp(name, "current") != 0)
+		return -EINVAL;
+
+	/* must be task querying itself or admin */
+	if (current != task && !capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	profile = aa_get_profile(task);
+	error = aa_getprocattr(profile, value, &len);
+	aa_put_profile(profile);
+	if (!error)
+		error = len;
+
+	return error;
+}
+
+static int apparmor_setprocattr(struct task_struct *task, char *name,
+				void *value, size_t size)
+{
+	char *command, *args;
+	int error;
+
+	if (strcmp(name, "current") != 0 || size == 0 || size >= PAGE_SIZE)
+		return -EINVAL;
+	args = value;
+	args[size] = '\0';
+	args = strstrip(args);
+	command = strsep(&args, " ");
+	if (!args)
+		return -EINVAL;
+	while (isspace(*args))
+		args++;
+	if (!*args)
+		return -EINVAL;
+
+	if (strcmp(command, "changehat") == 0) {
+		if (current != task)
+			return -EACCES;
+		error = aa_setprocattr_changehat(args);
+	} else if (strcmp(command, "setprofile")) {
+		struct aa_profile *profile;
+
+		/* Only an unconfined process with admin capabilities
+		 * may change the profile of another task.
+		 */
+
+		if (!capable(CAP_SYS_ADMIN))
+			return -EACCES;
+
+		profile = aa_get_profile(current);
+		if (profile) {
+			aa_put_profile(profile);
+			AA_WARN(GFP_KERNEL,
+				"Attempt by confined task %s(%d) "
+				"[user %d] to assign profile to task %s(%d)",
+				current->comm,
+				current->pid,
+				current->uid,
+				task->comm,
+				task->pid);
+			return -EACCES;
+		}
+		error = aa_setprocattr_setprofile(task, args);
+	} else {
+		AA_ERROR("Unknown setprocattr command '%.*s' "
+			"by task %s(%d) [user %d] for task %s(%d)",
+			size < 16 ? (int)size : 16,
+			command,
+			current->comm,
+			current->pid,
+			current->uid,
+			task->comm,
+			task->pid);
+		error = -EINVAL;
+	}
+
+	if (!error)
+		error = size;
+	return error;
+}
+
+struct security_operations apparmor_ops = {
+	.ptrace =			apparmor_ptrace,
+	.capget =			apparmor_capget,
+	.capset_check =			apparmor_capset_check,
+	.capset_set =			apparmor_capset_set,
+	.sysctl =			apparmor_sysctl,
+	.capable =			apparmor_capable,
+	.syslog =			apparmor_syslog,
+
+	.netlink_send =			apparmor_netlink_send,
+	.netlink_recv =			apparmor_netlink_recv,
+
+	.bprm_apply_creds =		apparmor_bprm_apply_creds,
+	.bprm_set_security =		apparmor_bprm_set_security,
+	.bprm_secureexec =		apparmor_bprm_secureexec,
+
+	.sb_mount =			apparmor_sb_mount,
+	.sb_umount =			apparmor_umount,
+
+	.inode_mkdir =			apparmor_inode_mkdir,
+	.inode_rmdir =			apparmor_inode_rmdir,
+	.inode_create =			apparmor_inode_create,
+	.inode_link =			apparmor_inode_link,
+	.inode_unlink =			apparmor_inode_unlink,
+	.inode_symlink =		apparmor_inode_symlink,
+	.inode_mknod =			apparmor_inode_mknod,
+	.inode_rename =			apparmor_inode_rename,
+	.inode_permission =		apparmor_inode_permission,
+	.inode_setattr =		apparmor_inode_setattr,
+	.inode_setxattr =		apparmor_inode_setxattr,
+	.inode_getxattr =		apparmor_inode_getxattr,
+	.inode_listxattr =		apparmor_inode_listxattr,
+	.inode_removexattr =		apparmor_inode_removexattr,
+	.file_permission =		apparmor_file_permission,
+	.file_alloc_security =		apparmor_file_alloc_security,
+	.file_free_security =		apparmor_file_free_security,
+	.file_mmap =			apparmor_file_mmap,
+	.file_mprotect =		apparmor_file_mprotect,
+
+	.task_create =			apparmor_task_create,
+	.task_alloc_security =		apparmor_task_alloc_security,
+	.task_free_security =		apparmor_task_free_security,
+	.task_post_setuid =		apparmor_task_post_setuid,
+	.task_reparent_to_init =	apparmor_task_reparent_to_init,
+
+	.getprocattr =			apparmor_getprocattr,
+	.setprocattr =			apparmor_setprocattr,
+};
+
+static int __init apparmor_init(void)
+{
+	int error;
+	const char *complainmsg = ": complainmode enabled";
+
+	if ((error = create_apparmorfs())) {
+		AA_ERROR("Unable to activate AppArmor filesystem\n");
+		goto createfs_out;
+	}
+
+	if ((error = alloc_null_complain_profile())){
+		AA_ERROR("Unable to allocate null complain profile\n");
+		goto alloc_out;
+	}
+
+	if ((error = register_security(&apparmor_ops))) {
+		AA_ERROR("Unable to load AppArmor\n");
+		goto register_security_out;
+	}
+
+	AA_INFO(GFP_KERNEL, "AppArmor initialized%s",
+		apparmor_complain ? complainmsg : "");
+
+	return error;
+
+register_security_out:
+	free_null_complain_profile();
+
+alloc_out:
+	destroy_apparmorfs();
+
+createfs_out:
+	return error;
+
+}
+
+static void __exit apparmor_exit(void)
+{
+	/* Remove and release all the profiles on the profile list. */
+	mutex_lock(&aa_interface_lock);
+	write_lock(&profile_list_lock);
+	while (!list_empty(&profile_list)) {
+		struct aa_profile *profile =
+			list_entry(profile_list.next, struct aa_profile, list);
+
+		/* Remove the profile from each task context it is on. */
+		lock_profile(profile);
+		profile->isstale = 1;
+		aa_unconfine_tasks(profile);
+		unlock_profile(profile);
+
+		/* Release the profile itself. */
+		list_del_init(&profile->list);
+		aa_put_profile(profile);
+	}
+	write_unlock(&profile_list_lock);
+
+	/* FIXME: cleanup profiles references on files */
+
+	free_null_complain_profile();
+
+	/**
+	 * Delay for an rcu cycle to make sure that all active task
+	 * context readers have finished, and all profiles have been
+	 * freed by their rcu callbacks.
+	 */
+	synchronize_rcu();
+
+	destroy_apparmorfs();
+	mutex_unlock(&aa_interface_lock);
+
+	if (unregister_security(&apparmor_ops))
+		AA_INFO(GFP_KERNEL, "Unable to properly unregister "
+			"AppArmor");
+
+	AA_INFO(GFP_KERNEL, "AppArmor protection removed");
+}
+
+module_init(apparmor_init);
+module_exit(apparmor_exit);
+
+MODULE_DESCRIPTION("AppArmor process confinement");
+MODULE_AUTHOR("Novell/Immunix, http://bugs.opensuse.org");
+MODULE_LICENSE("GPL");

-- 

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

* [AppArmor 39/41] AppArmor: Profile loading and manipulation, pathname matching
  2007-04-12  9:08 [AppArmor 00/41] AppArmor security module overview jjohansen
                   ` (37 preceding siblings ...)
  2007-04-12  9:08 ` [AppArmor 38/41] AppArmor: Module and LSM hooks jjohansen
@ 2007-04-12  9:08 ` jjohansen
  2007-04-12 10:28   ` Alan Cox
  2007-04-12 13:46   ` Andi Kleen
  2007-04-12  9:08 ` [AppArmor 40/41] AppArmor: all the rest jjohansen
                   ` (4 subsequent siblings)
  43 siblings, 2 replies; 187+ messages in thread
From: jjohansen @ 2007-04-12  9:08 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, linux-fsdevel, chrisw, John Johansen,
	Andreas Gruenbacher

[-- Attachment #1: apparmor-module_interface.diff --]
[-- Type: text/plain, Size: 25105 bytes --]

Pathname matching, transition table loading, profile loading and
manipulation.

Signed-off-by: John Johansen <jjohansen@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>

---
 security/apparmor/match.c            |  232 ++++++++++++
 security/apparmor/match.h            |   83 ++++
 security/apparmor/module_interface.c |  641 +++++++++++++++++++++++++++++++++++
 3 files changed, 956 insertions(+)

--- /dev/null
+++ b/security/apparmor/match.c
@@ -0,0 +1,232 @@
+/*
+ *	Copyright (C) 2007 Novell/SUSE
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License as
+ *	published by the Free Software Foundation, version 2 of the
+ *	License.
+ *
+ *	Regular expression transition table matching
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include "match.h"
+
+static struct table_header *unpack_table(void *blob, size_t bsize)
+{
+	struct table_header *table = NULL;
+	struct table_header th;
+	size_t tsize;
+
+	if (bsize < sizeof(struct table_header))
+		goto out;
+
+	th.td_id = ntohs(*(u16 *) (blob));
+	th.td_flags = ntohs(*(u16 *) (blob + 2));
+	th.td_lolen = ntohl(*(u32 *) (blob + 8));
+	blob += sizeof(struct table_header);
+
+	if (!(th.td_flags == YYTD_DATA16 || th.td_flags == YYTD_DATA32 ||
+		th.td_flags == YYTD_DATA8))
+		goto out;
+
+	tsize = table_size(th.td_lolen, th.td_flags);
+	if (bsize < tsize)
+		goto out;
+
+	table = kmalloc(tsize, GFP_KERNEL);
+	if (table) {
+		*table = th;
+		if (th.td_flags == YYTD_DATA8)
+			UNPACK_ARRAY(table->td_data, blob, th.td_lolen,
+				     u8, ntohb);
+		else if (th.td_flags == YYTD_DATA16)
+			UNPACK_ARRAY(table->td_data, blob, th.td_lolen,
+				     u16, ntohs);
+		else
+			UNPACK_ARRAY(table->td_data, blob, th.td_lolen,
+				     u32, ntohl);
+	}
+
+out:
+	return table;
+}
+
+int unpack_dfa(struct aa_dfa *dfa, void *blob, size_t size)
+{
+	int hsize, i;
+	int error = -ENOMEM;
+
+	/* get dfa table set header */
+	if (size < sizeof(struct table_set_header))
+		goto fail;
+
+	if (ntohl(*(u32 *)blob) != YYTH_MAGIC)
+		goto fail;
+
+	hsize = ntohl(*(u32 *)(blob + 4));
+	if (size < hsize)
+		goto fail;
+
+	blob += hsize;
+	size -= hsize;
+
+	error = -EPROTO;
+	while (size > 0) {
+		struct table_header *table;
+		table = unpack_table(blob, size);
+		if (!table)
+			goto fail;
+
+		switch(table->td_id) {
+		case YYTD_ID_ACCEPT:
+		case YYTD_ID_BASE:
+			dfa->tables[table->td_id - 1] = table;
+			if (table->td_flags != YYTD_DATA32)
+				goto fail;
+			break;
+		case YYTD_ID_DEF:
+		case YYTD_ID_NXT:
+		case YYTD_ID_CHK:
+			dfa->tables[table->td_id - 1] = table;
+			if (table->td_flags != YYTD_DATA16)
+				goto fail;
+			break;
+		case YYTD_ID_EC:
+			dfa->tables[table->td_id - 1] = table;
+			if (table->td_flags != YYTD_DATA8)
+				goto fail;
+			break;
+		default:
+			kfree(table);
+			goto fail;
+		}
+
+		blob += table_size(table->td_lolen, table->td_flags);
+		size -= table_size(table->td_lolen, table->td_flags);
+	}
+
+	return 0;
+
+fail:
+	for (i = 0; i < ARRAY_SIZE(dfa->tables); i++) {
+		if (dfa->tables[i]) {
+			kfree(dfa->tables[i]);
+			dfa->tables[i] = NULL;
+		}
+	}
+	return error;
+}
+
+/**
+ * verify_dfa - verify that all the transitions and states in the dfa tables
+ *              are in bounds.
+ * @dfa: dfa to test
+ *
+ * assumes dfa has gone through the verification done by unpacking
+ */
+int verify_dfa(struct aa_dfa *dfa)
+{
+	size_t i, state_count, trans_count;
+	int error = -EPROTO;
+
+	/* check that required tables exist */
+	if (!(dfa->tables[YYTD_ID_ACCEPT -1 ] &&
+	      dfa->tables[YYTD_ID_DEF - 1] &&
+	      dfa->tables[YYTD_ID_BASE - 1] &&
+	      dfa->tables[YYTD_ID_NXT - 1] &&
+	      dfa->tables[YYTD_ID_CHK - 1]))
+		goto out;
+
+	/* accept.size == default.size == base.size */
+	state_count = dfa->tables[YYTD_ID_BASE - 1]->td_lolen;
+	if (!(state_count == dfa->tables[YYTD_ID_DEF - 1]->td_lolen &&
+	      state_count == dfa->tables[YYTD_ID_ACCEPT - 1]->td_lolen))
+		goto out;
+
+	/* next.size == chk.size */
+	trans_count = dfa->tables[YYTD_ID_NXT - 1]->td_lolen;
+	if (trans_count != dfa->tables[YYTD_ID_CHK - 1]->td_lolen)
+		goto out;
+
+	/* if equivalence classes then its table size must be 256 */
+	if (dfa->tables[YYTD_ID_EC - 1] &&
+	    dfa->tables[YYTD_ID_EC - 1]->td_lolen != 256)
+		goto out;
+
+	for (i = 0; i < state_count; i++) {
+		if (DEFAULT_TABLE(dfa)[i] >= state_count)
+			goto out;
+		if (BASE_TABLE(dfa)[i] >= trans_count + 256)
+			goto out;
+	}
+
+	for (i = 0; i < trans_count ; i++) {
+		if (NEXT_TABLE(dfa)[i] >= state_count)
+			goto out;
+		if (CHECK_TABLE(dfa)[i] >= state_count)
+			goto out;
+	}
+
+	error = 0;
+out:
+	return error;
+}
+
+struct aa_dfa *aa_match_alloc(void)
+{
+	return kzalloc(sizeof(struct aa_dfa), GFP_KERNEL);
+}
+
+void aa_match_free(struct aa_dfa *dfa)
+{
+	if (dfa) {
+		int i;
+
+		for (i = 0; i < ARRAY_SIZE(dfa->tables); i++)
+			kfree(dfa->tables[i]);
+	}
+	kfree(dfa);
+}
+
+/**
+ * aa_dfa_match - match @path against @dfa starting in @state
+ * @dfa: the dfa to match @path against
+ * @state: the state to start matching in
+ * @path: the path to match against the dfa
+ *
+ * aa_dfa_match will match the full path length and return the state it
+ * finished matching in. The final state is used to look up the accepting
+ * label.
+ */
+unsigned int aa_dfa_match(struct aa_dfa *dfa, const char *str)
+{
+	u16 *def = DEFAULT_TABLE(dfa);
+	u32 *base = BASE_TABLE(dfa);
+	u16 *next = NEXT_TABLE(dfa);
+	u16 *check = CHECK_TABLE(dfa);
+	unsigned int state = 1, pos;
+
+	/* current state is <state>, matching character *str */
+	if (dfa->tables[YYTD_ID_EC - 1]) {
+		u8 *equiv = EQUIV_TABLE(dfa);
+		while (*str) {
+			pos = base[state] + equiv[(u8)*str++];
+			if (check[pos] == state)
+				state = next[pos];
+			else
+				state = def[state];
+		}
+	} else {
+		while (*str) {
+			pos = base[state] + (u8)*str++;
+			if (check[pos] == state)
+				state = next[pos];
+			else
+				state = def[state];
+		}
+	}
+	return ACCEPT_TABLE(dfa)[state];
+}
--- /dev/null
+++ b/security/apparmor/match.h
@@ -0,0 +1,83 @@
+/*
+ *	Copyright (C) 2007 Novell/SUSE
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License as
+ *	published by the Free Software Foundation, version 2 of the
+ *	License.
+ *
+ *	AppArmor submodule (match) prototypes
+ */
+
+#ifndef __MATCH_H
+#define __MATCH_H
+
+/**
+ * The format used for transition tables is based on the GNU flex table
+ * file format (--tables-file option; see Table File Format in the flex
+ * info pages and the flex sources for documentation). The magic number
+ * used in the header is 0x1B5E783D insted of 0xF13C57B1 though, because
+ * the YY_ID_CHK (check) and YY_ID_DEF (default) tables are used
+ * slightly differently (see the apparmor-parser package).
+ */
+
+#define YYTH_MAGIC	0x1B5E783D
+
+struct table_set_header {
+	u32		th_magic;	/* YYTH_MAGIC */
+	u32		th_hsize;
+	u32		th_ssize;
+	u16		th_flags;
+	char		th_version[];
+};
+
+#define	YYTD_ID_ACCEPT	1
+#define YYTD_ID_BASE	2
+#define YYTD_ID_CHK	3
+#define YYTD_ID_DEF	4
+#define YYTD_ID_EC	5
+#define YYTD_ID_META	6
+#define YYTD_ID_NXT	8
+
+
+#define YYTD_DATA8	1
+#define YYTD_DATA16	2
+#define YYTD_DATA32	4
+
+struct table_header {
+	u16		td_id;
+	u16		td_flags;
+	u32		td_hilen;
+	u32		td_lolen;
+	char		td_data[];
+};
+
+#define DEFAULT_TABLE(DFA) ((u16 *)((DFA)->tables[YYTD_ID_DEF - 1]->td_data))
+#define BASE_TABLE(DFA) ((u32 *)((DFA)->tables[YYTD_ID_BASE - 1]->td_data))
+#define NEXT_TABLE(DFA) ((u16 *)((DFA)->tables[YYTD_ID_NXT - 1]->td_data))
+#define CHECK_TABLE(DFA) ((u16 *)((DFA)->tables[YYTD_ID_CHK - 1]->td_data))
+#define EQUIV_TABLE(DFA) ((u8 *)((DFA)->tables[YYTD_ID_EC - 1]->td_data))
+#define ACCEPT_TABLE(DFA) ((u32 *)((DFA)->tables[YYTD_ID_ACCEPT - 1]->td_data))
+
+struct aa_dfa {
+	struct table_header *tables[YYTD_ID_NXT];
+};
+
+#define ntohb(X) (X)
+
+#define UNPACK_ARRAY(TABLE, BLOB, LEN, TYPE, NTOHX) \
+	do { \
+		typeof(LEN) __i; \
+		TYPE *__t = (TYPE *) TABLE; \
+		TYPE *__b = (TYPE *) BLOB; \
+		for (__i = 0; __i < LEN; __i++) { \
+			__t[__i] = NTOHX(__b[__i]); \
+		} \
+	} while (0)
+
+static inline size_t table_size(size_t len, size_t el_size)
+{
+	return ALIGN(sizeof(struct table_header) + len * el_size, 8);
+}
+
+#endif /* __MATCH_H */
--- /dev/null
+++ b/security/apparmor/module_interface.c
@@ -0,0 +1,641 @@
+/*
+ *	Copyright (C) 1998-2007 Novell/SUSE
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License as
+ *	published by the Free Software Foundation, version 2 of the
+ *	License.
+ *
+ *	AppArmor userspace policy interface
+ */
+
+#include <asm/unaligned.h>
+
+#include "apparmor.h"
+#include "inline.h"
+
+/*
+ * This mutex is used to synchronize profile adds, replacements, and
+ * removals: we only allow one of these operations at a time.
+ * We do not use the profile list lock here in order to avoid blocking
+ * exec during those operations.  (Exec involves a profile list lookup
+ * for named-profile transitions.)
+ */
+DEFINE_MUTEX(aa_interface_lock);
+
+/*
+ * The AppArmor interface treats data as a type byte followed by the
+ * actual data.  The interface has the notion of a a named entry
+ * which has a name (AA_NAME typecode followed by name string) followed by
+ * the entries typecode and data.  Named types allow for optional
+ * elements and extensions to be added and tested for without breaking
+ * backwards compatability.
+ */
+
+enum aa_code {
+	AA_U8,
+	AA_U16,
+	AA_U32,
+	AA_U64,
+	AA_NAME,	/* same as string except it is items name */
+	AA_STRING,
+	AA_BLOB,
+	AA_STRUCT,
+	AA_STRUCTEND,
+	AA_LIST,
+	AA_LISTEND,
+};
+
+/*
+ * aa_ext is the read of the buffer containing the serialized profile.  The
+ * data is copied into a kernel buffer in apparmorfs and then handed off to
+ * the unpack routines.
+ */
+struct aa_ext {
+	void *start;
+	void *end;
+	void *pos;	/* pointer to current position in the buffer */
+	u32 version;
+};
+
+static inline int aa_inbounds(struct aa_ext *e, size_t size)
+{
+	return (e->pos + size <= e->end);
+}
+
+/**
+ * aa_u16_chunck - test and do bounds checking for a u16 size based chunk
+ * @e: serialized data read head
+ * @chunk: start address for chunk of data
+ *
+ * return the size of chunk found with the read head at the end of
+ * the chunk.
+ */
+static size_t aa_is_u16_chunk(struct aa_ext *e, char **chunk)
+{
+	void *pos = e->pos;
+	size_t size = 0;
+
+	if (!aa_inbounds(e, sizeof(u16)))
+		goto fail;
+	size = le16_to_cpu(get_unaligned((u16 *)e->pos));
+	e->pos += sizeof(u16);
+	if (!aa_inbounds(e, size))
+		goto fail;
+	*chunk = e->pos;
+	e->pos += size;
+	return size;
+
+fail:
+	e->pos = pos;
+	return 0;
+}
+
+static inline int aa_is_X(struct aa_ext *e, enum aa_code code)
+{
+	if (!aa_inbounds(e, 1))
+		return 0;
+	if (*(u8 *) e->pos != code)
+		return 0;
+	e->pos++;
+	return 1;
+}
+
+/**
+ * aa_is_nameX - check is the next element is of type X with a name of @name
+ * @e: serialized data extent information
+ * @code: type code
+ * @name: name to match to the serialized element.
+ *
+ * check that the next serialized data element is of type X and has a tag
+ * name @name.  If @name is specified then there must be a matching
+ * name element in the stream.  If @name is NULL any name element will be
+ * skipped and only the typecode will be tested.
+ * returns 1 on success (both type code and name tests match) and the read
+ * head is advanced past the headers
+ * returns %0 if either match failes, the read head does not move
+ */
+static int aa_is_nameX(struct aa_ext *e, enum aa_code code, const char *name)
+{
+	void *pos = e->pos;
+	/*
+	 * Check for presence of a tagname, and if present name size
+	 * AA_NAME tag value is a u16.
+	 */
+	if (aa_is_X(e, AA_NAME)) {
+		char *tag;
+		size_t size = aa_is_u16_chunk(e, &tag);
+		/* if a name is specified it must match. otherwise skip tag */
+		if (name && (!size || strcmp(name, tag)))
+			goto fail;
+	} else if (name) {
+		/* if a name is specified and there is no name tag fail */
+		goto fail;
+	}
+
+	/* now check if type code matches */
+	if (aa_is_X(e, code))
+		return 1;
+
+fail:
+	e->pos = pos;
+	return 0;
+}
+
+static int aa_is_u32(struct aa_ext *e, u32 *data, const char *name)
+{
+	void *pos = e->pos;
+	if (aa_is_nameX(e, AA_U32, name)) {
+		if (!aa_inbounds(e, sizeof(u32)))
+			goto fail;
+		if (data)
+			*data = le32_to_cpu(get_unaligned((u32 *)e->pos));
+		e->pos += sizeof(u32);
+		return 1;
+	}
+fail:
+	e->pos = pos;
+	return 0;
+}
+
+static size_t aa_is_blob(struct aa_ext *e, char **blob, const char *name)
+{
+	void *pos = e->pos;
+	if (aa_is_nameX(e, AA_BLOB, name)) {
+		u32 size;
+		if (!aa_inbounds(e, sizeof(u32)))
+			goto fail;
+		size = le32_to_cpu(get_unaligned((u32 *)e->pos));
+		e->pos += sizeof(u32);
+		if (aa_inbounds(e, (size_t) size)) {
+			* blob = e->pos;
+			e->pos += size;
+			return size;
+		}
+	}
+fail:
+	e->pos = pos;
+	return 0;
+}
+
+static int aa_is_dynstring(struct aa_ext *e, char **string, const char *name)
+{
+	char *src_str;
+	size_t size = 0;
+	void *pos = e->pos;
+	*string = NULL;
+	if (aa_is_nameX(e, AA_STRING, name) &&
+	    (size = aa_is_u16_chunk(e, &src_str))) {
+		char *str;
+		if (!(str = kmalloc(size, GFP_KERNEL)))
+			goto fail;
+		memcpy(str, src_str, size);
+		*string = str;
+	}
+
+	return size;
+
+fail:
+	e->pos = pos;
+	return 0;
+}
+
+/**
+ * aa_unpack_dfa - unpack a file rule dfa
+ * @e: serialized data extent information
+ *
+ * returns dfa or ERR_PTR
+ */
+struct aa_dfa *aa_unpack_dfa(struct aa_ext *e)
+{
+	char *blob = NULL;
+	size_t size, error = 0;
+	struct aa_dfa *dfa = NULL;
+
+	size = aa_is_blob(e, &blob, "aadfa");
+	if (size) {
+		dfa = aa_match_alloc();
+		if (dfa) {
+			/*
+			 * The dfa is aligned with in the blob to 8 bytes
+			 * from the beginning of the stream.
+			 */
+			size_t sz = blob - (char *) e->start;
+			size_t pad = ALIGN(sz, 8) - sz;
+			error = unpack_dfa(dfa, blob + pad, size - pad);
+			if (!error)
+				error = verify_dfa(dfa);
+		} else {
+			error = -ENOMEM;
+		}
+
+		if (error) {
+			aa_match_free(dfa);
+			dfa = ERR_PTR(error);
+		}
+	}
+
+	return dfa;
+}
+
+/**
+ * aa_unpack_profile - unpack a serialized profile
+ * @e: serialized data extent information
+ * @error: error code returned if unpacking fails
+ */
+static struct aa_profile *aa_unpack_profile(struct aa_ext *e)
+{
+	struct aa_profile *profile = NULL;
+
+	int error = -EPROTO;
+
+	profile = alloc_aa_profile();
+	if (!profile)
+		return ERR_PTR(-ENOMEM);
+
+	/* check that we have the right struct being passed */
+	if (!aa_is_nameX(e, AA_STRUCT, "profile"))
+		goto fail;
+	if (!aa_is_dynstring(e, &profile->name, NULL))
+		goto fail;
+
+	/* per profile debug flags (complain, audit) */
+	if (!aa_is_nameX(e, AA_STRUCT, "flags"))
+		goto fail;
+	if (!aa_is_u32(e, NULL, NULL))
+		goto fail;
+	if (!aa_is_u32(e, &(profile->flags.complain), NULL))
+		goto fail;
+	if (!aa_is_u32(e, &(profile->flags.audit), NULL))
+		goto fail;
+	if (!aa_is_nameX(e, AA_STRUCTEND, NULL))
+		goto fail;
+
+	if (!aa_is_u32(e, &(profile->capabilities), NULL))
+		goto fail;
+
+	/* get file rules */
+	profile->file_rules = aa_unpack_dfa(e);
+	if (IS_ERR(profile->file_rules)) {
+		error = PTR_ERR(profile->file_rules);
+		profile->file_rules = NULL;
+		goto fail;
+	}
+
+	/* get optional subprofiles */
+	if (aa_is_nameX(e, AA_LIST, "hats")) {
+		while (!aa_is_nameX(e, AA_LISTEND, NULL)) {
+			struct aa_profile *subprofile;
+			subprofile = aa_unpack_profile(e);
+			if (IS_ERR(subprofile)) {
+				error = PTR_ERR(subprofile);
+				goto fail;
+			}
+			subprofile->parent = profile;
+			list_add(&subprofile->list, &profile->sub);
+		}
+	}
+
+	if (!aa_is_nameX(e, AA_STRUCTEND, NULL))
+		goto fail;
+
+	return profile;
+
+fail:
+	AA_WARN(GFP_KERNEL, "Invalid profile %s",
+		profile && profile->name ? profile->name : "unknown");
+
+	if (profile)
+		free_aa_profile(profile);
+
+	return ERR_PTR(error);
+}
+
+/**
+ * aa_unpack_profile_wrapper - unpack a serialized base profile
+ * @e: serialized data extent information
+ *
+ * check interface version unpack a profile and all its hats and patch
+ * in any extra information that the profile needs.
+ */
+static struct aa_profile *aa_unpack_profile_wrapper(struct aa_ext *e)
+{
+	struct aa_profile *profile = aa_unpack_profile(e);
+	if (!IS_ERR(profile) &&
+	    (!list_empty(&profile->sub) || profile->flags.complain)) {
+		int error;
+		if ((error = attach_nullprofile(profile))) {
+			aa_put_profile(profile);
+			return ERR_PTR(error);
+		}
+	}
+
+	return profile;
+}
+
+/**
+ * aa_verify_head - unpack serialized stream header
+ * @e: serialized data read head
+ *
+ * returns error or 0 if header is good
+ */
+static int aa_verify_header(struct aa_ext *e)
+{
+	/* get the interface version */
+	if (!aa_is_u32(e, &e->version, "version")) {
+		AA_WARN(GFP_KERNEL, "Interface version missing");
+		return -EPROTONOSUPPORT;
+	}
+
+	/* check that the interface version is currently supported */
+	if (e->version != 3) {
+		AA_WARN(GFP_KERNEL,
+			"Unsupported interface version (%d)", e->version);
+		return -EPROTONOSUPPORT;
+	}
+	return 0;
+}
+
+/**
+ * aa_add_profile - Unpack and add a new profile to the profile list
+ * @data: serialized data stream
+ * @size: size of the serialized data stream
+ */
+ssize_t aa_add_profile(void *data, size_t size)
+{
+	struct aa_profile *profile = NULL;
+	struct aa_ext e = {
+		.start = data,
+		.end = data + size,
+		.pos = data
+	};
+	ssize_t error = aa_verify_header(&e);
+	if (error)
+		return error;
+
+	profile = aa_unpack_profile_wrapper(&e);
+	if (IS_ERR(profile))
+		return PTR_ERR(profile);
+
+	mutex_lock(&aa_interface_lock);
+	write_lock(&profile_list_lock);
+	if (__aa_find_profile(profile->name, &profile_list)) {
+		/* A profile with this name exists already. */
+		write_unlock(&profile_list_lock);
+		mutex_unlock(&aa_interface_lock);
+		aa_put_profile(profile);
+		return -EEXIST;
+	}
+	list_add(&profile->list, &profile_list);
+	write_unlock(&profile_list_lock);
+	mutex_unlock(&aa_interface_lock);
+
+	return size;
+}
+
+/**
+ * task_replace - replace a task's profile
+ * @task: task to replace profile on
+ * @new_cxt: new aa_task_context to do replacement with
+ * @new_profile: new profile
+ */
+static inline void task_replace(struct task_struct *task,
+				struct aa_task_context *new_cxt,
+				struct aa_profile *new_profile)
+{
+	struct aa_task_context *cxt = aa_task_context(task);
+
+	AA_DEBUG("%s: replacing profile for task %s(%d) "
+		 "profile=%s (%p) hat=%s (%p)\n",
+		 __FUNCTION__,
+		 cxt->task->comm, cxt->task->pid,
+		 cxt->profile->parent->name, cxt->profile->parent,
+		 cxt->profile->name, cxt->profile);
+
+	if (cxt->profile != cxt->profile->parent) {
+		struct aa_profile *hat;
+
+		/*
+		 * The old profile was in a hat, check to see if the new
+		 * profile has an equivalent hat.
+		 */
+		hat = __aa_find_profile(cxt->profile->name, &new_profile->sub);
+
+		if (!hat)
+			hat = aa_dup_profile(new_profile->null_profile);
+
+		aa_change_task_context(task, new_cxt, hat, cxt->hat_magic);
+		aa_put_profile(hat);
+	} else
+		aa_change_task_context(task, new_cxt, new_profile,
+				       cxt->hat_magic);
+}
+
+/**
+ * aa_replace_profile - replace a profile on the profile list
+ * @udata: serialized data stream
+ * @size: size of the serialized data stream
+ *
+ * unpack and replace a profile on the profile list and uses of that profile
+ * by any aa_task_context.  If the profile does not exist on the profile list
+ * it is added.  Return %0 or error.
+ */
+ssize_t aa_replace_profile(void *udata, size_t size)
+{
+	struct aa_profile *old_profile, *new_profile;
+	struct aa_task_context *new_cxt;
+	struct aa_ext e = {
+		.start = udata,
+		.end = udata + size,
+		.pos = udata
+	};
+	ssize_t error = aa_verify_header(&e);
+	if (error)
+		return error;
+
+	new_profile = aa_unpack_profile_wrapper(&e);
+	if (IS_ERR(new_profile))
+		return PTR_ERR(new_profile);
+
+	mutex_lock(&aa_interface_lock);
+	write_lock(&profile_list_lock);
+	old_profile = __aa_find_profile(new_profile->name, &profile_list);
+	if (old_profile) {
+		lock_profile(old_profile);
+		old_profile->isstale = 1;
+		unlock_profile(old_profile);
+		list_del_init(&old_profile->list);
+	}
+	list_add(&new_profile->list, &profile_list);
+	write_unlock(&profile_list_lock);
+
+	if (!old_profile)
+		goto out;
+
+	/*
+	 * Replacement needs to allocate a new aa_task_context for each
+	 * task confined by old_profile.  To do this the profile locks
+	 * are only held when the actual switch is done per task.  While
+	 * looping to allocate a new aa_task_context the old_task list
+	 * may get shorter if tasks exit/change their profile but will
+	 * not get longer as new task will not use old_profile detecting
+	 * that is stale.
+	 */
+	do {
+		new_cxt = aa_alloc_task_context(GFP_KERNEL | __GFP_NOFAIL);
+
+		lock_both_profiles(old_profile, new_profile);
+		if (!list_empty(&old_profile->task_contexts)) {
+			struct task_struct *task =
+				list_entry(old_profile->task_contexts.next,
+					   struct aa_task_context, list)->task;
+			task_lock(task);
+			task_replace(task, new_cxt, new_profile);
+			task_unlock(task);
+			new_cxt = NULL;
+		}
+		unlock_both_profiles(old_profile, new_profile);
+	} while (!new_cxt);
+	aa_free_task_context(new_cxt);
+	aa_put_profile(old_profile);
+
+out:
+	mutex_unlock(&aa_interface_lock);
+	return size;
+}
+
+/**
+ * aa_remove_profile - remove a profile from the system
+ * @name: name of the profile to remove
+ * @size: size of the name
+ *
+ * remove a profile from the profile list and all aa_task_context references
+ * to said profile.
+ */
+ssize_t aa_remove_profile(const char *name, size_t size)
+{
+	struct aa_profile *profile;
+
+	mutex_lock(&aa_interface_lock);
+	write_lock(&profile_list_lock);
+	profile = __aa_find_profile(name, &profile_list);
+	if (!profile) {
+		write_unlock(&profile_list_lock);
+		mutex_unlock(&aa_interface_lock);
+		return -ENOENT;
+	}
+
+	/* Remove the profile from each task context it is on. */
+	lock_profile(profile);
+	profile->isstale = 1;
+	aa_unconfine_tasks(profile);
+	unlock_profile(profile);
+
+	/* Release the profile itself. */
+	list_del_init(&profile->list);
+	aa_put_profile(profile);
+	write_unlock(&profile_list_lock);
+	mutex_unlock(&aa_interface_lock);
+
+	return size;
+}
+
+/**
+ * free_aa_profile_kref - free aa_profile by kref (called by aa_put_profile)
+ * @kr: kref callback for freeing of a profile
+ */
+void free_aa_profile_kref(struct kref *kref)
+{
+	struct aa_profile *p=container_of(kref, struct aa_profile, count);
+
+	free_aa_profile(p);
+}
+
+/**
+ * alloc_aa_profile - allocate, initialize and return a new profile
+ * Returns NULL on failure.
+ */
+struct aa_profile *alloc_aa_profile(void)
+{
+	struct aa_profile *profile;
+
+	profile = kzalloc(sizeof(*profile), GFP_KERNEL);
+	AA_DEBUG("%s(%p)\n", __FUNCTION__, profile);
+	if (profile) {
+		profile->parent = profile;
+		INIT_LIST_HEAD(&profile->list);
+		INIT_LIST_HEAD(&profile->sub);
+		kref_init(&profile->count);
+		INIT_LIST_HEAD(&profile->task_contexts);
+		spin_lock_init(&profile->lock);
+	}
+	return profile;
+}
+
+/**
+ * free_aa_profile - free a profile
+ * @profile: the profile to free
+ *
+ * Free a profile, its hats and null_profile. All references to the profile,
+ * its hats and null_profile must have been put.
+ *
+ * If the profile was referenced from a task context, free_aa_profile() will
+ * be called from an rcu callback routine, so we must not sleep here.
+ */
+void free_aa_profile(struct aa_profile *profile)
+{
+	struct aa_profile *p, *ptmp;
+
+	AA_DEBUG("%s(%p)\n", __FUNCTION__, profile);
+
+	if (!profile)
+		return;
+
+	/* profile is still on global profile list -- invalid */
+	if (!list_empty(&profile->list)) {
+		AA_ERROR("%s: internal error, "
+			 "profile '%s' still on global list\n",
+			 __FUNCTION__,
+			 profile->name);
+		BUG();
+	}
+
+	aa_match_free(profile->file_rules);
+
+	/*
+	 * Use free_aa_profile instead of aa_put_profile to destroy the
+	 * null_profile, because the null_profile use the same reference
+	 * counting as hats, ie. the count goes to the base profile.
+	 */
+	free_aa_profile(profile->null_profile);
+	list_for_each_entry_safe(p, ptmp, &profile->sub, list) {
+		list_del_init(&p->list);
+		p->parent = p;
+		aa_put_profile(p);
+	}
+
+	if (profile->name) {
+		AA_DEBUG("%s: %s\n", __FUNCTION__, profile->name);
+		kfree(profile->name);
+	}
+
+	kfree(profile);
+}
+
+/**
+ * aa_unconfine_tasks - remove tasks on a profile's task context list
+ * @profile: profile to remove tasks from
+ *
+ * Assumes that @profile lock is held.
+ */
+void aa_unconfine_tasks(struct aa_profile *profile)
+{
+	while (!list_empty(&profile->task_contexts)) {
+		struct task_struct *task =
+			list_entry(profile->task_contexts.next,
+				   struct aa_task_context, list)->task;
+		task_lock(task);
+		aa_change_task_context(task, NULL, NULL, 0);
+		task_unlock(task);
+	}
+}

-- 

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

* [AppArmor 40/41] AppArmor: all the rest
  2007-04-12  9:08 [AppArmor 00/41] AppArmor security module overview jjohansen
                   ` (38 preceding siblings ...)
  2007-04-12  9:08 ` [AppArmor 39/41] AppArmor: Profile loading and manipulation, pathname matching jjohansen
@ 2007-04-12  9:08 ` jjohansen
  2007-04-12 10:32   ` Al Viro
  2007-04-12  9:08 ` [AppArmor 41/41] Add AppArmor LSM to security/Makefile jjohansen
                   ` (3 subsequent siblings)
  43 siblings, 1 reply; 187+ messages in thread
From: jjohansen @ 2007-04-12  9:08 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, linux-fsdevel, chrisw, John Johansen,
	Andreas Gruenbacher

[-- Attachment #1: apparmor-misc.diff --]
[-- Type: text/plain, Size: 31490 bytes --]

All the things that didn't nicely fit in a category on their own: kbuild
code, declararions and inline functions, /sys/kernel/security/apparmor
filesystem for controlling apparmor from user space, profile list
functions, locking documentation, /proc/$pid/task/$tid/attr/current
access.

Signed-off-by: John Johansen <jjohansen@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>

---
 security/apparmor/Kconfig      |    9 +
 security/apparmor/Makefile     |   13 +
 security/apparmor/apparmor.h   |  282 +++++++++++++++++++++++++++++++++++++++++
 security/apparmor/apparmorfs.c |  248 ++++++++++++++++++++++++++++++++++++
 security/apparmor/inline.h     |  219 +++++++++++++++++++++++++++++++
 security/apparmor/list.c       |   94 +++++++++++++
 security/apparmor/locking.txt  |   59 ++++++++
 security/apparmor/procattr.c   |  143 ++++++++++++++++++++
 8 files changed, 1067 insertions(+)

--- /dev/null
+++ b/security/apparmor/Kconfig
@@ -0,0 +1,9 @@
+config SECURITY_APPARMOR
+	tristate "AppArmor support"
+	depends on SECURITY!=n
+	help
+	  This enables the AppArmor security module.
+	  Required userspace tools (if they are not included in your
+	  distribution) and further information may be found at
+	  <http://forge.novell.com/modules/xfmod/project/?apparmor>
+	  If you are unsure how to answer this question, answer N.
--- /dev/null
+++ b/security/apparmor/Makefile
@@ -0,0 +1,13 @@
+# Makefile for AppArmor Linux Security Module
+#
+obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o
+
+apparmor-y := main.o list.o procattr.o lsm.o apparmorfs.o \
+	      module_interface.o match.o
+
+quiet_cmd_make-caps = GEN     $@
+cmd_make-caps = sed -n -e "/CAP_FS_MASK/d" -e "s/^\#define[ \\t]\\+CAP_\\([A-Z0-9_]\\+\\)[ \\t]\\+\\([0-9]\\+\\)\$$/[\\2]  = \"\\1\",/p" $< | tr A-Z a-z > $@
+
+$(obj)/main.o : $(obj)/capability_names.h
+$(obj)/capability_names.h : $(srctree)/include/linux/capability.h
+	$(call cmd,make-caps)
--- /dev/null
+++ b/security/apparmor/apparmor.h
@@ -0,0 +1,282 @@
+/*
+ *	Copyright (C) 1998-2007 Novell/SUSE
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License as
+ *	published by the Free Software Foundation, version 2 of the
+ *	License.
+ *
+ *	AppArmor internal prototypes
+ */
+
+#ifndef __APPARMOR_H
+#define __APPARMOR_H
+
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/binfmts.h>
+#include <linux/rcupdate.h>
+
+/*
+ * We use MAY_READ, MAY_WRITE, MAY_EXEC, and the following flags for
+ * profile permissions (we don't use MAY_APPEND):
+ */
+#define AA_MAY_LINK			0x0010
+#define AA_EXEC_INHERIT			0x0020
+#define AA_EXEC_UNCONFINED		0x0040
+#define AA_EXEC_PROFILE			0x0080
+#define AA_EXEC_MMAP			0x0100
+#define AA_EXEC_UNSAFE			0x0200
+
+#define AA_EXEC_MODIFIERS		(AA_EXEC_INHERIT | \
+					 AA_EXEC_UNCONFINED | \
+					 AA_EXEC_PROFILE)
+
+#define AA_SECURE_EXEC_NEEDED		1
+
+/* Control parameters (0 or 1), settable thru module/boot flags or
+ * via /sys/kernel/security/apparmor/control */
+extern int apparmor_complain;
+extern int apparmor_debug;
+extern int apparmor_audit;
+extern int apparmor_logsyscall;
+extern unsigned int apparmor_path_max;
+
+#define PROFILE_COMPLAIN(_profile) \
+	(apparmor_complain == 1 || ((_profile) && (_profile)->flags.complain))
+
+#define APPARMOR_COMPLAIN(_cxt) \
+	(apparmor_complain == 1 || \
+	 ((_cxt) && (_cxt)->profile && (_cxt)->profile->flags.complain))
+
+#define PROFILE_AUDIT(_profile) \
+	(apparmor_audit == 1 || ((_profile) && (_profile)->flags.audit))
+
+#define APPARMOR_AUDIT(_cxt) \
+	(apparmor_audit == 1 || \
+	 ((_cxt) && (_cxt)->profile && (_cxt)->profile->flags.audit))
+
+/*
+ * DEBUG remains global (no per profile flag) since it is mostly used in sysctl
+ * which is not related to profile accesses.
+ */
+
+#define AA_DEBUG(fmt, args...)						\
+	do {								\
+		if (apparmor_debug)					\
+			printk(KERN_DEBUG "AppArmor: " fmt, ##args);	\
+	} while (0)
+#define AA_INFO(gfp, fmt, args...) \
+	do { \
+		printk(KERN_INFO "AppArmor: " fmt "\n", ##args); \
+		aa_audit_message(NULL, (gfp), 0, fmt, ##args); \
+	} while (0)
+#define AA_WARN(gfp, fmt, args...) \
+	aa_audit_message(NULL, (gfp), 0, fmt, ##args);
+
+#define AA_REJECT_MSG(p, gfp, fmt, args...) \
+	aa_audit_message((p), (gfp), 0, \
+			"REJECTING " fmt \
+			" (%s(%d) profile %s active %s)", ##args, \
+			current->comm, current->pid, \
+			(p)->parent->name, (p)->name)
+
+#define AA_ERROR(fmt, args...)	printk(KERN_ERR "AppArmor: " fmt, ##args)
+
+/* struct aa_profile - basic confinement data
+ * @parent: non refcounted pointer to parent profile
+ * @name: the profiles name
+ * @file_rules: dfa containing the profiles file rules
+ * @list: list this profile is on
+ * @sub: profiles list of subprofiles (HATS)
+ * @flags: flags controlling profile behavior
+ * @null_profile: if needed per profile learning and null confinement profile
+ * @isstale: flag indicating if profile is stale
+ * @capabilities: capabilities granted by the process
+ * @count: reference count of the profile
+ *
+ * The AppArmor profile contains the basic confinement data.  Each profile
+ * has a name and potentially a list of profile entries. All profiles are
+ * on the profile_list.
+ *
+ * The task_contexts list and the isstale flag are protected by the
+ * profile lock.
+ *
+ * If a task context is moved between two profiles, we first need to grab
+ * both profile locks. lock_both_profiles() does that in a deadlock-safe
+ * way.
+ */
+struct aa_profile {
+	struct aa_profile *parent;
+	char *name;
+	struct aa_dfa *file_rules;
+	struct list_head list;
+	struct list_head sub;
+	struct {
+		int complain;
+		int audit;
+	} flags;
+	struct aa_profile *null_profile;
+	int isstale;
+
+	kernel_cap_t capabilities;
+	struct kref count;
+	struct list_head task_contexts;
+	spinlock_t lock;
+	unsigned long int_flags;
+};
+
+extern struct list_head profile_list;
+extern rwlock_t profile_list_lock;
+extern struct mutex aa_interface_lock;
+
+/**
+ * struct aa_task_context - primary label for confined tasks
+ * @profile: the current profile
+ * @hat_magic: the magic token controling the ability to leave a hat
+ * @list: list this aa_task_context is on
+ * @task: task that the aa_task_context confines
+ * @rcu: rcu head used when freeing the aa_task_context
+ * @caps_logged: caps that have previously generated log entries
+ *
+ * Contains the task's current profile (which could change due to
+ * change_hat).  Plus the hat_magic needed during change_hat.
+ */
+struct aa_task_context {
+	struct aa_profile *profile;	/* The current profile */
+	u64 hat_magic;			/* used with change_hat */
+	struct list_head list;
+	struct task_struct *task;
+	struct rcu_head rcu;
+	kernel_cap_t caps_logged;
+};
+
+extern struct aa_profile *null_complain_profile;
+
+/* aa_audit - AppArmor auditing structure
+ * Structure is populated by access control code and passed to aa_audit which
+ * provides for a single point of logging.
+ */
+
+struct aa_audit {
+	unsigned short type, flags;
+	unsigned int result;
+	gfp_t gfp_mask;
+	int error_code;
+
+	const char *operation;
+	const char *name;
+	union {
+		int capability;
+		int mask;
+	};
+	union {
+		const void *pval;
+		va_list vaval;
+	};
+};
+
+/* audit types */
+#define AA_AUDITTYPE_FILE	1
+#define AA_AUDITTYPE_DIR	2
+#define AA_AUDITTYPE_ATTR	3
+#define AA_AUDITTYPE_XATTR	4
+#define AA_AUDITTYPE_LINK	5
+#define AA_AUDITTYPE_CAP	6
+#define AA_AUDITTYPE_MSG	7
+#define AA_AUDITTYPE_SYSCALL	8
+#define AA_AUDITTYPE__END	9
+
+/* audit flags */
+#define AA_AUDITFLAG_AUDITSS_SYSCALL 1 /* log syscall context */
+#define AA_AUDITFLAG_LOGERR	     2 /* log operations that failed due to
+					   non permission errors  */
+
+#define HINT_UNKNOWN_HAT "unknown_hat"
+#define HINT_FORK "fork"
+#define HINT_MANDPROF "missing_mandatory_profile"
+#define HINT_CHGPROF "changing_profile"
+#define HINT_PTRACE "ptrace"
+
+#define LOG_HINT(p, gfp, hint, fmt, args...) \
+	aa_audit_message((p), (gfp), 0, \
+			"LOGPROF-HINT " hint " " fmt \
+			" (%s(%d) profile %s active %s)", ##args, \
+			current->comm, current->pid, \
+			(p)->parent->name, (p)->name)
+
+/* Flags for the permission check functions */
+#define AA_CHECK_LEAF	1  /* this is the leaf lookup component */
+#define AA_CHECK_FD	2  /* coming from a file descriptor */
+#define AA_CHECK_DIR	4  /* file type is directory */
+
+/* main.c */
+extern int alloc_null_complain_profile(void);
+extern void free_null_complain_profile(void);
+extern int attach_nullprofile(struct aa_profile *profile);
+extern int aa_audit_message(struct aa_profile *profile, gfp_t gfp, int,
+			    const char *, ...);
+extern int aa_audit_syscallreject(struct aa_profile *profile, gfp_t gfp,
+				  const char *);
+extern int aa_audit(struct aa_profile *profile, const struct aa_audit *);
+
+extern int aa_attr(struct aa_profile *profile, struct dentry *dentry,
+		   struct vfsmount *mnt, struct iattr *iattr);
+extern int aa_perm_xattr(struct aa_profile *profile, struct dentry *dentry,
+			 struct vfsmount *mnt, const char *operation,
+			 const char *xattr_xattr, int mask, int check);
+extern int aa_capability(struct aa_task_context *cxt, int cap);
+extern int aa_perm(struct aa_profile *profile, struct dentry *dentry,
+		   struct vfsmount *mnt, int mask, int check);
+extern int aa_perm_dir(struct aa_profile *profile, struct dentry *dentry,
+		       struct vfsmount *mnt, const char *operation, int mask);
+extern int aa_link(struct aa_profile *profile,
+		   struct dentry *link, struct vfsmount *link_mnt,
+		   struct dentry *target, struct vfsmount *target_mnt);
+extern int aa_clone(struct task_struct *task);
+extern int aa_register(struct linux_binprm *bprm);
+extern void aa_release(struct task_struct *task);
+extern int aa_change_hat(const char *id, u64 hat_magic);
+extern struct aa_profile *__aa_find_profile(const char *name,
+					    struct list_head *list);
+extern struct aa_profile *__aa_replace_profile(struct task_struct *task,
+					       struct aa_profile *profile,
+					       u32 hat_magic);
+extern struct aa_task_context *lock_task_and_profiles(struct task_struct *task,
+						      struct aa_profile *profile);
+extern void aa_change_task_context(struct task_struct *task,
+				   struct aa_task_context *new_cxt,
+				   struct aa_profile *profile, u64 hat_magic);
+extern int aa_may_ptrace(struct aa_task_context *cxt,
+			 struct aa_profile *tracee);
+
+/* list.c */
+extern void aa_profilelist_release(void);
+
+/* module_interface.c */
+extern ssize_t aa_add_profile(void *, size_t);
+extern ssize_t aa_replace_profile(void *, size_t);
+extern ssize_t aa_remove_profile(const char *, size_t);
+extern struct aa_profile *alloc_aa_profile(void);
+extern void free_aa_profile(struct aa_profile *profile);
+extern void free_aa_profile_kref(struct kref *kref);
+extern void aa_unconfine_tasks(struct aa_profile *profile);
+
+/* procattr.c */
+extern int aa_getprocattr(struct aa_profile *profile, char **string,
+			  unsigned *len);
+extern int aa_setprocattr_changehat(char *args);
+extern int aa_setprocattr_setprofile(struct task_struct *task, char *args);
+
+/* apparmorfs.c */
+extern int create_apparmorfs(void);
+extern void destroy_apparmorfs(void);
+
+/* match.c */
+extern struct aa_dfa *aa_match_alloc(void);
+extern void aa_match_free(struct aa_dfa *dfa);
+extern int unpack_dfa(struct aa_dfa *dfa, void *blob, size_t size);
+extern int verify_dfa(struct aa_dfa *dfa);
+extern unsigned int aa_dfa_match(struct aa_dfa *dfa, const char *str);
+
+#endif  /* __APPARMOR_H */
--- /dev/null
+++ b/security/apparmor/apparmorfs.c
@@ -0,0 +1,248 @@
+/*
+ *	Copyright (C) 1998-2007 Novell/SUSE
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License as
+ *	published by the Free Software Foundation, version 2 of the
+ *	License.
+ *
+ *	AppArmor filesystem (part of securityfs)
+ */
+
+#include <linux/security.h>
+#include <linux/vmalloc.h>
+#include <linux/module.h>
+#include <linux/seq_file.h>
+#include <asm/uaccess.h>
+
+#include "apparmor.h"
+#include "inline.h"
+
+static char *aa_simple_write_to_buffer(const char __user *userbuf,
+				       size_t alloc_size, size_t copy_size,
+				       loff_t *pos, const char *msg)
+{
+	struct aa_profile *profile;
+	char *data;
+
+	if (*pos != 0) {
+		/* only writes from pos 0, that is complete writes */
+		data = ERR_PTR(-ESPIPE);
+		goto out;
+	}
+
+	/*
+	 * Don't allow confined processes to load/replace/remove profiles.
+	 * No sane person would add rules allowing this to a profile
+	 * but we enforce the restriction anyways.
+	 */
+	profile = aa_get_profile(current);
+	if (profile) {
+		AA_WARN(GFP_KERNEL, "REJECTING access to profile %s (%s(%d) "
+			"profile %s active %s)",
+			msg, current->comm, current->pid,
+			profile->parent->name, profile->name);
+		aa_put_profile(profile);
+
+		data = ERR_PTR(-EPERM);
+		goto out;
+	}
+
+	data = vmalloc(alloc_size);
+	if (data == NULL) {
+		data = ERR_PTR(-ENOMEM);
+		goto out;
+	}
+
+	if (copy_from_user(data, userbuf, copy_size)) {
+		vfree(data);
+		data = ERR_PTR(-EFAULT);
+		goto out;
+	}
+
+out:
+	return data;
+}
+
+/* apparmor/profiles */
+extern struct seq_operations apparmorfs_profiles_op;
+
+static int aa_profiles_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &apparmorfs_profiles_op);
+}
+
+
+static int aa_profiles_release(struct inode *inode, struct file *file)
+{
+	return seq_release(inode, file);
+}
+
+static struct file_operations apparmorfs_profiles_fops = {
+	.open =		aa_profiles_open,
+	.read =		seq_read,
+	.llseek =	seq_lseek,
+	.release =	aa_profiles_release,
+};
+
+/* apparmor/matching */
+static ssize_t aa_matching_read(struct file *file, char __user *buf,
+			       size_t size, loff_t *ppos)
+{
+	const char *matching = "pattern=aadfa";
+
+	return simple_read_from_buffer(buf, size, ppos, matching,
+				       strlen(matching));
+}
+
+static struct file_operations apparmorfs_matching_fops = {
+	.read = 	aa_matching_read,
+};
+
+/* apparmor/.load */
+static ssize_t aa_profile_load(struct file *f, const char __user *buf,
+			       size_t size, loff_t *pos)
+{
+	char *data;
+	ssize_t error;
+
+	data = aa_simple_write_to_buffer(buf, size, size, pos, "load");
+
+	error = PTR_ERR(data);
+	if (!IS_ERR(data)) {
+		error = aa_add_profile(data, size);
+		vfree(data);
+	}
+
+	return error;
+}
+
+
+static struct file_operations apparmorfs_profile_load = {
+	.write = aa_profile_load
+};
+
+/* apparmor/.replace */
+static ssize_t aa_profile_replace(struct file *f, const char __user *buf,
+				  size_t size, loff_t *pos)
+{
+	char *data;
+	ssize_t error;
+
+	data = aa_simple_write_to_buffer(buf, size, size, pos, "replacement");
+
+	error = PTR_ERR(data);
+	if (!IS_ERR(data)) {
+		error = aa_replace_profile(data, size);
+		vfree(data);
+	}
+
+	return error;
+}
+
+
+static struct file_operations apparmorfs_profile_replace = {
+	.write = aa_profile_replace
+};
+
+/* apparmor/.remove */
+static ssize_t aa_profile_remove(struct file *f, const char __user *buf,
+				  size_t size, loff_t *pos)
+{
+	char *data;
+	ssize_t error;
+
+	/*
+	 * aa_remove_profile needs a null terminated string so 1 extra
+	 * byte is allocated and the copied data is null terminated.
+	 */
+	data = aa_simple_write_to_buffer(buf, size + 1, size, pos, "removal");
+
+	error = PTR_ERR(data);
+	if (!IS_ERR(data)) {
+		data[size] = 0;
+		error = aa_remove_profile(data, size);
+		vfree(data);
+	}
+
+	return error;
+}
+
+static struct file_operations apparmorfs_profile_remove = {
+	.write = aa_profile_remove
+};
+
+static struct dentry *apparmor_dentry;
+
+static void aafs_remove(const char *name)
+{
+	struct dentry *dentry;
+
+	dentry = lookup_one_len(name, apparmor_dentry, strlen(name));
+	if (dentry && !IS_ERR(dentry))
+		securityfs_remove(dentry);
+}
+
+static int aafs_create(const char *name, int mask, struct file_operations *fops)
+{
+	struct dentry *dentry;
+
+	dentry = securityfs_create_file(name, S_IFREG | mask, apparmor_dentry,
+					NULL, fops);
+
+	return IS_ERR(dentry) ? PTR_ERR(dentry) : 0;
+}
+
+void destroy_apparmorfs(void)
+{
+	if (apparmor_dentry) {
+		aafs_remove(".remove");
+		aafs_remove(".replace");
+		aafs_remove(".load");
+		aafs_remove("matching");
+		aafs_remove("profiles");
+		securityfs_remove(apparmor_dentry);
+		apparmor_dentry = NULL;
+	}
+}
+
+int create_apparmorfs(void)
+{
+	int error;
+
+	if (apparmor_dentry) {
+		AA_ERROR("%s: AppArmor securityfs already exists\n",
+			__FUNCTION__);
+		return -EEXIST;
+	}
+
+	apparmor_dentry = securityfs_create_dir("apparmor", NULL);
+	if (IS_ERR(apparmor_dentry)) {
+		error = PTR_ERR(apparmor_dentry);
+		apparmor_dentry = NULL;
+ 		goto error;
+	}
+	error = aafs_create("profiles", 0440, &apparmorfs_profiles_fops);
+	if (error)
+		goto error;
+	error = aafs_create("matching", 0444, &apparmorfs_matching_fops);
+	if (error)
+		goto error;
+	error = aafs_create(".load", 0640, &apparmorfs_profile_load);
+	if (error)
+		goto error;
+	error = aafs_create(".replace", 0640, &apparmorfs_profile_replace);
+	if (error)
+		goto error;
+	error = aafs_create(".remove", 0640, &apparmorfs_profile_remove);
+	if (error)
+		goto error;
+
+	return 0;
+
+error:
+	destroy_apparmorfs();
+	AA_ERROR("Error creating AppArmor securityfs\n");
+	return error;
+}
+
--- /dev/null
+++ b/security/apparmor/inline.h
@@ -0,0 +1,219 @@
+/*
+ *	Copyright (C) 1998-2007 Novell/SUSE
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License as
+ *	published by the Free Software Foundation, version 2 of the
+ *	License.
+ */
+
+#ifndef __INLINE_H
+#define __INLINE_H
+
+#include <linux/sched.h>
+
+static inline int mediated_filesystem(struct inode *inode)
+{
+	return !(inode->i_sb->s_flags & MS_NOUSER);
+}
+
+static inline struct aa_task_context *aa_task_context(struct task_struct *task)
+{
+	return rcu_dereference((struct aa_task_context *)task->security);
+}
+
+/**
+ * aa_dup_profile - increment refcount on profile @p
+ * @p: profile
+ */
+static inline struct aa_profile *aa_dup_profile(struct aa_profile *p)
+{
+	if (p)
+		kref_get(&(p->parent->count));
+
+	return p;
+}
+
+/**
+ * aa_put_profile - decrement refcount on profile @p
+ * @p: profile
+ */
+static inline void aa_put_profile(struct aa_profile *p)
+{
+	if (p)
+		kref_put(&p->parent->count, free_aa_profile_kref);
+}
+
+static inline struct aa_profile *aa_get_profile(struct task_struct *task)
+{
+	struct aa_task_context *cxt;
+	struct aa_profile *profile = NULL;
+
+	rcu_read_lock();
+	cxt = aa_task_context(task);
+	if (cxt) {
+		profile = cxt->profile;
+		aa_dup_profile(profile);
+	}
+	rcu_read_unlock();
+
+	return profile;
+}
+
+static inline struct aa_profile *aa_find_profile(const char *name)
+{
+	struct aa_profile *profile = NULL;
+
+	read_lock(&profile_list_lock);
+	profile = aa_dup_profile(__aa_find_profile(name, &profile_list));
+	read_unlock(&profile_list_lock);
+
+	return profile;
+}
+
+static inline struct aa_task_context *aa_alloc_task_context(gfp_t flags)
+{
+	struct aa_task_context *cxt;
+
+	cxt = kzalloc(sizeof(*cxt), flags);
+	if (cxt) {
+		INIT_LIST_HEAD(&cxt->list);
+		INIT_RCU_HEAD(&cxt->rcu);
+	}
+
+	return cxt;
+}
+
+static inline void aa_free_task_context(struct aa_task_context *cxt)
+{
+	if (cxt) {
+		aa_put_profile(cxt->profile);
+		kfree(cxt);
+	}
+}
+
+/**
+ * lock_profile - lock a profile
+ * @profile: the profile to lock
+ *
+ * While the profile is locked, local interrupts are disabled. This also
+ * gives us RCU reader safety.
+ */
+static inline void lock_profile(struct aa_profile *profile)
+{
+	/* We always lock top-level profiles instead of children. */
+	if (profile)
+		profile = profile->parent;
+
+	/*
+	 * Lock the profile.
+	 *
+	 * Need to disable interrupts here because this lock is used in
+	 * the task_free_security hook, which may run in RCU context.
+	 */
+	if (profile)
+		spin_lock_irqsave(&profile->lock, profile->int_flags);
+}
+
+/**
+ * unlock_profile - unlock a profile
+ * @profile: the profile to unlock
+ */
+static inline void unlock_profile(struct aa_profile *profile)
+{
+	/* We always lock top-level profiles instead of children. */
+	if (profile)
+		profile = profile->parent;
+
+	/* Unlock the profile. */
+	if (profile)
+		spin_unlock_irqrestore(&profile->lock, profile->int_flags);
+}
+
+/**
+ * lock_both_profiles  -  lock two profiles in a deadlock-free way
+ * @profile1:	profile to lock (may be NULL)
+ * @profile2:	profile to lock (may be NULL)
+ *
+ * The order in which profiles are passed into lock_both_profiles() /
+ * unlock_both_profiles() does not matter.
+ * While the profile is locked, local interrupts are disabled. This also
+ * gives us RCU reader safety.
+ */
+static inline void lock_both_profiles(struct aa_profile *profile1,
+				      struct aa_profile *profile2)
+{
+	/* We always lock top-level profiles instead of children. */
+	if (profile1)
+		profile1 = profile1->parent;
+	if (profile2)
+		profile2 = profile2->parent;
+
+	/*
+	 * Lock the two profiles.
+	 *
+	 * We need to disable interrupts because the profile locks are
+	 * used in the task_free_security hook, which may run in RCU
+	 * context.
+	 *
+	 * Do not nest spin_lock_irqsave()/spin_unlock_irqresore():
+	 * interrupts only need to be turned off once.
+	 */
+	if (!profile1 || profile1 == profile2) {
+		if (profile2)
+			spin_lock_irqsave(&profile2->lock, profile2->int_flags);
+	} else if (profile1 > profile2) {
+		/* profile1 cannot be NULL here. */
+		spin_lock_irqsave(&profile1->lock, profile1->int_flags);
+		if (profile2)
+			spin_lock(&profile2->lock);
+
+	} else {
+		/* profile2 cannot be NULL here. */
+		spin_lock_irqsave(&profile2->lock, profile2->int_flags);
+		spin_lock(&profile1->lock);
+	}
+}
+
+/**
+ * unlock_both_profiles  -  unlock two profiles in a deadlock-free way
+ * @profile1:	profile to unlock (may be NULL)
+ * @profile2:	profile to unlock (may be NULL)
+ *
+ * The order in which profiles are passed into lock_both_profiles() /
+ * unlock_both_profiles() does not matter.
+ * While the profile is locked, local interrupts are disabled. This also
+ * gives us RCU reader safety.
+ */
+static inline void unlock_both_profiles(struct aa_profile *profile1,
+				        struct aa_profile *profile2)
+{
+	/* We always lock top-level profiles instead of children. */
+	if (profile1)
+		profile1 = profile1->parent;
+	if (profile2)
+		profile2 = profile2->parent;
+
+	/* Unlock the two profiles. */
+	if (!profile1 || profile1 == profile2) {
+		if (profile2)
+			spin_unlock_irqrestore(&profile2->lock,
+					       profile2->int_flags);
+	} else if (profile1 > profile2) {
+		/* profile1 cannot be NULL here. */
+		if (profile2)
+			spin_unlock(&profile2->lock);
+		spin_unlock_irqrestore(&profile1->lock, profile1->int_flags);
+	} else {
+		/* profile2 cannot be NULL here. */
+		spin_unlock(&profile1->lock);
+		spin_unlock_irqrestore(&profile2->lock, profile2->int_flags);
+	}
+}
+
+static inline unsigned int aa_match(struct aa_dfa *dfa, const char *pathname)
+{
+	        return dfa ? aa_dfa_match(dfa, pathname) : 0;
+}
+
+#endif /* __INLINE_H__ */
--- /dev/null
+++ b/security/apparmor/list.c
@@ -0,0 +1,94 @@
+/*
+ *	Copyright (C) 1998-2007 Novell/SUSE
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License as
+ *	published by the Free Software Foundation, version 2 of the
+ *	License.
+ *
+ *	AppArmor Profile List Management
+ */
+
+#include <linux/seq_file.h>
+#include "apparmor.h"
+#include "inline.h"
+
+/* list of all profiles and lock */
+LIST_HEAD(profile_list);
+rwlock_t profile_list_lock = RW_LOCK_UNLOCKED;
+
+/**
+ * __aa_find_profile  -  look up a profile on the profile list
+ * @name: name of profile to find
+ * @head: list to search
+ *
+ * Returns a pointer to the profile on the list, or NULL if no profile
+ * called @name exists. The caller must hold the profile_list_lock.
+ */
+struct aa_profile *__aa_find_profile(const char *name, struct list_head *head)
+{
+	struct aa_profile *profile;
+
+	list_for_each_entry(profile, head, list) {
+		if (!strcmp(profile->name, name))
+			return profile;
+	}
+
+	return NULL;
+}
+
+/**
+ * aa_profilelist_release - Remove all profiles from profile_list
+ */
+void aa_profilelist_release(void)
+{
+	struct aa_profile *p, *tmp;
+
+	write_lock(&profile_list_lock);
+	list_for_each_entry_safe(p, tmp, &profile_list, list) {
+		list_del_init(&p->list);
+		aa_put_profile(p);
+	}
+	write_unlock(&profile_list_lock);
+}
+
+static void *p_start(struct seq_file *f, loff_t *pos)
+{
+	struct aa_profile *node;
+	loff_t l = *pos;
+
+	read_lock(&profile_list_lock);
+	list_for_each_entry(node, &profile_list, list)
+		if (!l--)
+			return node;
+	return NULL;
+}
+
+static void *p_next(struct seq_file *f, void *p, loff_t *pos)
+{
+	struct list_head *lh = ((struct aa_profile *)p)->list.next;
+	(*pos)++;
+	return lh == &profile_list ?
+			NULL : list_entry(lh, struct aa_profile, list);
+}
+
+static void p_stop(struct seq_file *f, void *v)
+{
+	read_unlock(&profile_list_lock);
+}
+
+static int seq_show_profile(struct seq_file *f, void *v)
+{
+	struct aa_profile *profile = (struct aa_profile *)v;
+	seq_printf(f, "%s (%s)\n", profile->name,
+		   PROFILE_COMPLAIN(profile) ? "complain" : "enforce");
+	return 0;
+}
+
+/* Used in apparmorfs.c */
+struct seq_operations apparmorfs_profiles_op = {
+	.start =	p_start,
+	.next =		p_next,
+	.stop =		p_stop,
+	.show =		seq_show_profile,
+};
--- /dev/null
+++ b/security/apparmor/locking.txt
@@ -0,0 +1,59 @@
+Locking in AppArmor
+===================
+
+Lock hierarchy:
+
+	aa_interface_lock
+	  profile_list_lock
+	    aa_profile->lock
+	      task_lock()
+
+
+Which lock protects what?
+
+	/-----------------------+-------------------------------\
+	| Variable		| Lock				|
+	>-----------------------+-------------------------------<
+	| profile_list		| profile_list_lock		|
+	+-----------------------+-------------------------------+
+	| aa_profile		| (reference count)		|
+	+-----------------------+-------------------------------+
+	| aa_profile->		| aa_profile->lock		|
+	|   isstale,		|				|
+	|   task_contexts	|				|
+	+-----------------------+-------------------------------+
+	| task_struct->security	| read: RCU			|
+	|			| write: task_lock()		|
+	+-----------------------+-------------------------------+
+	| aa_profile->sub	| handle on the profile (list	|
+	|			| is never modified)		|
+	\-----------------------+-------------------------------/
+
+(Obviously, the list_heads embedded in data structures are always
+protected with the lock that also protects the list.)
+
+When moving a task context from one profile to another, we grab both
+profile locks with lock_both_profiles(). This ensures that both locks
+are always taken in the same order, and so we won't deadlock.
+
+Since task_struct->security is RCU protected the aa_task_struct it
+references is only guarenteed to exist for the rcu cycle.  Where
+aa_task_context->profile is needed in blocking operations the
+profile's reference count is incremented and the profile reference
+is used.
+
+Profiles on profile_list are never stale: when a profile becomes stale,
+it is removed from profile_list at the same time (under profile_list_lock
+and aa_profile->lock).
+
+The aa_interface_lock is taken whenever user-space modifies the profile
+list, and can sleep. This ensures that profile loading/replacement/removal
+won't race with itself. We release the profile_list_lock as soon as
+possible to avoid stalling exec during profile loading/replacement/removal.
+
+lock_dep reports a false 'possible irq lock inversion dependency detected'
+when the profile lock is taken in aa_release.  This is due to that the
+task_lock is often taken inside the profile lock but other kernel code
+takes the task_lock with interrupts enabled.  A deadlock will not actually
+occur because apparmor does not take the task_lock in hard_irq or soft_irq
+context.
--- /dev/null
+++ b/security/apparmor/procattr.c
@@ -0,0 +1,143 @@
+/*
+ *	Copyright (C) 1998-2007 Novell/SUSE
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License as
+ *	published by the Free Software Foundation, version 2 of the
+ *	License.
+ *
+ *	AppArmor /proc/pid/attr handling
+ */
+
+#include "apparmor.h"
+#include "inline.h"
+
+int aa_getprocattr(struct aa_profile *profile, char **string, unsigned *len)
+{
+	char *str;
+
+	if (profile) {
+		const char *mode_str = PROFILE_COMPLAIN(profile) ?
+			" (complain)" : " (enforce)";
+
+		*len = ((profile != profile->parent) ?
+		           strlen(profile->parent->name) + 1 : 0) +
+		       strlen(mode_str) + strlen(profile->name) + 1;
+		str = kmalloc(*len, GFP_ATOMIC);
+		if (!str)
+			return -ENOMEM;
+
+		if (profile != profile->parent) {
+			memcpy(str, profile->parent->name,
+			       strlen(profile->parent->name));
+			str += strlen(profile->parent->name);
+			*str++ = '^';
+		}
+		memcpy(str, profile->name, strlen(profile->name));
+		str += strlen(profile->name);
+		memcpy(str, mode_str, strlen(mode_str));
+		str += strlen(mode_str);
+		*str++ = '\n';
+		str -= *len;
+	} else {
+		const char *unconfined_str = "unconfined\n";
+
+		*len = strlen(unconfined_str);
+		str = kmalloc(*len, GFP_ATOMIC);
+		if (!str)
+			return -ENOMEM;
+
+		memcpy(str, unconfined_str, *len);
+	}
+	*string = str;
+
+	return 0;
+}
+
+int aa_setprocattr_changehat(char *args)
+{
+	char *hat;
+	u64 magic;
+
+	magic = simple_strtoull(args, &hat, 16);
+	if (hat == args || *hat != '^') {
+		AA_ERROR("change_hat: Invalid input '%s'", args);
+		return -EINVAL;
+	}
+	hat++;  /* skip ^ */
+	if (!*hat)
+		hat = NULL;
+	if (!hat && !magic) {
+		AA_ERROR("change_hat: Invalid input, NULL hat and NULL magic");
+		return -EINVAL;
+	}
+
+	AA_DEBUG("%s: Magic 0x%llx Hat '%s'\n",
+		 __FUNCTION__, magic, hat ? hat : NULL);
+
+	return aa_change_hat(hat, magic);
+}
+
+int aa_setprocattr_setprofile(struct task_struct *task, char *args)
+{
+	struct aa_profile *old_profile, *new_profile;
+
+	AA_DEBUG("%s: current %s(%d)\n",
+		 __FUNCTION__, current->comm, current->pid);
+
+repeat:
+	if (strcmp(args, "unconfined") == 0)
+		new_profile = NULL;
+	else {
+		new_profile = aa_find_profile(args);
+		if (!new_profile) {
+			AA_WARN(GFP_KERNEL,
+				"Unable to switch task %s(%d) to profile"
+				"'%s'. No such profile.",
+				task->comm, task->pid,
+				args);
+
+			return -EINVAL;
+		}
+	}
+
+	old_profile = __aa_replace_profile(task, new_profile, 0);
+	if (IS_ERR(old_profile)) {
+		int error;
+
+		aa_put_profile(new_profile);
+		error = PTR_ERR(old_profile);
+		if (error == -ESTALE)
+			goto repeat;
+		return error;
+	}
+
+	if (new_profile) {
+		AA_WARN(GFP_KERNEL,
+			"Switching task %s(%d) "
+			"profile %s active %s to new profile %s",
+			task->comm, task->pid,
+			old_profile ? old_profile->parent->name :
+				"unconfined",
+			old_profile ? old_profile->name : "unconfined",
+			args);
+	} else {
+		if (old_profile) {
+			AA_WARN(GFP_KERNEL,
+				"Unconfining task %s(%d) "
+				"profile %s active %s",
+				task->comm, task->pid,
+				old_profile->parent->name,
+				old_profile->name);
+		} else {
+			AA_WARN(GFP_KERNEL,
+				"task %s(%d) is already unconfined",
+				task->comm, task->pid);
+		}
+	}
+
+	aa_put_profile(old_profile);
+	aa_put_profile(new_profile);
+
+	return 0;
+}

-- 

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

* [AppArmor 41/41] Add AppArmor LSM to security/Makefile
  2007-04-12  9:08 [AppArmor 00/41] AppArmor security module overview jjohansen
                   ` (39 preceding siblings ...)
  2007-04-12  9:08 ` [AppArmor 40/41] AppArmor: all the rest jjohansen
@ 2007-04-12  9:08 ` jjohansen
  2007-04-12 10:33 ` [AppArmor 00/41] AppArmor security module overview Shaya Potter
                   ` (2 subsequent siblings)
  43 siblings, 0 replies; 187+ messages in thread
From: jjohansen @ 2007-04-12  9:08 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, linux-fsdevel, chrisw, John Johansen,
	Andreas Gruenbacher

[-- Attachment #1: apparmor-intree.diff --]
[-- Type: text/plain, Size: 859 bytes --]

Signed-off-by: John Johansen <jjohansen@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>

---
 security/Kconfig  |    1 +
 security/Makefile |    1 +
 2 files changed, 2 insertions(+)

--- a/security/Kconfig
+++ b/security/Kconfig
@@ -94,6 +94,7 @@ config SECURITY_ROOTPLUG
 	  If you are unsure how to answer this question, answer N.
 
 source security/selinux/Kconfig
+source security/apparmor/Kconfig
 
 endmenu
 
--- a/security/Makefile
+++ b/security/Makefile
@@ -14,5 +14,6 @@ endif
 obj-$(CONFIG_SECURITY)			+= security.o dummy.o inode.o
 # Must precede capability.o in order to stack properly.
 obj-$(CONFIG_SECURITY_SELINUX)		+= selinux/built-in.o
+obj-$(CONFIG_SECURITY_APPARMOR)		+= commoncap.o apparmor/
 obj-$(CONFIG_SECURITY_CAPABILITIES)	+= commoncap.o capability.o
 obj-$(CONFIG_SECURITY_ROOTPLUG)		+= commoncap.o root_plug.o

-- 

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

* Re: [AppArmor 31/41] Fix __d_path() for lazy unmounts and make it unambiguous; exclude unreachable mount points from /proc/mounts
  2007-04-12  9:08 ` [AppArmor 31/41] Fix __d_path() for lazy unmounts and make it unambiguous; exclude unreachable mount points from /proc/mounts jjohansen
@ 2007-04-12  9:58   ` Alan Cox
  2007-04-15 17:40     ` Andreas Gruenbacher
  0 siblings, 1 reply; 187+ messages in thread
From: Alan Cox @ 2007-04-12  9:58 UTC (permalink / raw)
  To: jjohansen
  Cc: linux-kernel, linux-security-module, linux-fsdevel, chrisw,
	Andreas Gruenbacher, Andrew Morton

> Third, sys_getcwd() shouldn't return disconnected paths.  The patch checks for
> that, and makes it fail with -ENOENT in that case

That is a fairly significant and sudden change to the existing
kernel/user interface.

> Fourth, this now allows us to tell unreachable mount points from reachable
> ones when generating the /proc/mounts and /proc/$pid/mountstats files. 
> Unreachable mount points are not interesting to processes (they can't get
> there, anyway), so we hide unreachable mounts.  In particular, ordinary

This is untrue. The process can get there (via fd passing with another
task) and the process can be producing output for the human operators,
who most definitely need to know and see this stuff.

> Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
> Reviewed-by: NeilBrown <neilb@suse.de>
> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

I don't think this is fit to apply in current form. The hiding of mounts
and mountstats is the wrong approach. The changes to getcwd behaviour
bother me too as we are changing user space behaviour without warning.

The general idea of pushing some of the fail detect logic into __d_path()
seems good though.

Alan

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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-04-12  9:08 ` [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook jjohansen
@ 2007-04-12 10:06   ` Christoph Hellwig
  2007-04-16 16:11     ` [nameidata 1/2] Don't pass NULL nameidata to vfs_create Andreas Gruenbacher
  2007-04-16 16:29     ` [nameidata 2/2] Pass no useless nameidata to the create, lookup, and permission IOPs Andreas Gruenbacher
  2007-04-12 10:12   ` [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook Al Viro
  1 sibling, 2 replies; 187+ messages in thread
From: Christoph Hellwig @ 2007-04-12 10:06 UTC (permalink / raw)
  To: jjohansen
  Cc: linux-kernel, linux-security-module, linux-fsdevel, chrisw,
	Tony Jones, Andreas Gruenbacher

On Thu, Apr 12, 2007 at 02:08:10AM -0700, jjohansen@suse.de wrote:
> This is needed for computing pathnames in the AppArmor LSM.
> 
> Signed-off-by: Tony Jones <tonyj@suse.de>
> Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
> Signed-off-by: John Johansen <jjohansen@suse.de>
> 
> ---
>  fs/namei.c               |    2 +-
>  include/linux/security.h |    9 ++++++---
>  security/dummy.c         |    2 +-
>  security/selinux/hooks.c |    3 ++-
>  4 files changed, 10 insertions(+), 6 deletions(-)
> 
> --- a/fs/namei.c
> +++ b/fs/namei.c
> @@ -1503,7 +1503,7 @@ int vfs_create(struct inode *dir, struct
>  		return -EACCES;	/* shouldn't it be ENOSYS? */
>  	mode &= S_IALLUGO;
>  	mode |= S_IFREG;
> -	error = security_inode_create(dir, dentry, mode);
> +	error = security_inode_create(dir, dentry, nd ? nd->mnt : NULL, mode);

Once again very strong NACK.  Every conditional passing of vfsmounts get my
veto.  As mentioned last time if you really want this send a patch series
first that passed the vfsmount consistantly.


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

* Re: [AppArmor 03/41] Remove redundant check from proc_sys_setattr()
  2007-04-12  9:08 ` [AppArmor 03/41] Remove redundant check from proc_sys_setattr() jjohansen
@ 2007-04-12 10:10   ` Alan Cox
  0 siblings, 0 replies; 187+ messages in thread
From: Alan Cox @ 2007-04-12 10:10 UTC (permalink / raw)
  To: jjohansen
  Cc: linux-kernel, linux-security-module, linux-fsdevel, chrisw,
	Steve Beattie, Andreas Gruenbacher, John Johansen

On Thu, 12 Apr 2007 02:08:12 -0700
jjohansen@suse.de wrote:

> notify_change() already calls security_inode_setattr() before
> calling iop->setattr.

This is a behaviour change on all of these and limits some behaviour of
existing established security modules

When inode_change_ok is called it has side effects. This includes
clearing the SGID bit on attribute changes caused by chmod. If you make
this change the results of some rulesets may be different before or
after the change is made.

I'm not saying the change is wrong but it does change behaviour so that
needs looking at closely (ditto all other attribute twiddles)

Alan




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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-04-12  9:08 ` [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook jjohansen
  2007-04-12 10:06   ` Christoph Hellwig
@ 2007-04-12 10:12   ` Al Viro
  2007-05-23 19:06     ` Andreas Gruenbacher
  1 sibling, 1 reply; 187+ messages in thread
From: Al Viro @ 2007-04-12 10:12 UTC (permalink / raw)
  To: jjohansen
  Cc: linux-kernel, linux-security-module, linux-fsdevel, chrisw,
	Tony Jones, Andreas Gruenbacher

On Thu, Apr 12, 2007 at 02:08:10AM -0700, jjohansen@suse.de wrote:
> This is needed for computing pathnames in the AppArmor LSM.

Which is an argument against said LSM in current form.


> -	error = security_inode_create(dir, dentry, mode);
> +	error = security_inode_create(dir, dentry, nd ? nd->mnt : NULL, mode);

is a clear sign that interface is wrong.  Leaving aside the general
idiocy of "we prohibit to do something with file if mounted here,
but if there's another mountpoint, well, we just miss", an API of that
kind is just plain wrong.  Either you can live without seeing vfsmount
in that method (in which case you shouldn't pass it at all), or you
have a hole.

NACK.

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

* Re: [AppArmor 38/41] AppArmor: Module and LSM hooks
  2007-04-12  9:08 ` [AppArmor 38/41] AppArmor: Module and LSM hooks jjohansen
@ 2007-04-12 10:21   ` Alan Cox
  2007-04-16 21:37     ` John Johansen
  0 siblings, 1 reply; 187+ messages in thread
From: Alan Cox @ 2007-04-12 10:21 UTC (permalink / raw)
  To: jjohansen
  Cc: linux-kernel, linux-security-module, linux-fsdevel, chrisw,
	John Johansen, Andreas Gruenbacher

> +
> +	/**
> +	 * parent can ptrace child when
> +	 * - parent is unconfined
> +	 * - parent is in complain mode
> +	 * - parent and child are confined by the same profile
> +	 */

Your profiles are name based. That means the same profile in a different
namespace does different things. It would be a very odd case where it
mattered but surely the parent ptrace child rule should also require that
the parent and child are in the same namespace when using apparmor name
based security.

> +static int apparmor_capget(struct task_struct *task,
> +			    kernel_cap_t *effective,
> +			    kernel_cap_t *inheritable,
> +			    kernel_cap_t *permitted)
> +{
> +	return cap_capget(task, effective, inheritable, permitted);
> +}

Pointless function should go away.

> +static int apparmor_sysctl(struct ctl_table *table, int op)
> +{
> +	int error = 0;
> +
> +	if ((op & 002) && !capable(CAP_SYS_ADMIN))
> +		error = aa_reject_syscall(current, GFP_KERNEL,
> +					  "sysctl (write)");
> +
> +	return error;

The usual file permission security override is DAC not ADMIN. What is the
logic of this choice.

> +}
> +
> +static int apparmor_syslog(int type)
> +{
> +	return cap_syslog(type);
> +}

More pointless functions to delete.



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

* Re: [AppArmor 39/41] AppArmor: Profile loading and manipulation, pathname matching
  2007-04-12  9:08 ` [AppArmor 39/41] AppArmor: Profile loading and manipulation, pathname matching jjohansen
@ 2007-04-12 10:28   ` Alan Cox
  2007-04-12 13:46   ` Andi Kleen
  1 sibling, 0 replies; 187+ messages in thread
From: Alan Cox @ 2007-04-12 10:28 UTC (permalink / raw)
  To: jjohansen
  Cc: linux-kernel, linux-security-module, linux-fsdevel, chrisw,
	John Johansen, Andreas Gruenbacher

> +	th.td_id = ntohs(*(u16 *) (blob));
> +	th.td_flags = ntohs(*(u16 *) (blob + 2));
> +	th.td_lolen = ntohl(*(u32 *) (blob + 8));

Use cpu_to and _to_cpu functions for here so it is clear the intended
direction and endianness.

> +
> +static inline int aa_inbounds(struct aa_ext *e, size_t size)
> +{
> +	return (e->pos + size <= e->end);
> +}

Can e->pos + size ever overflow. If so this check isn't safe.


> + * aa_unpack_profile - unpack a serialized profile
> + * @e: serialized data extent information
> + * @error: error code returned if unpacking fails
> + */
> +static struct aa_profile *aa_unpack_profile(struct aa_ext *e)
> +{
> +	struct aa_profile *profile = NULL;
> +

> +	/* get optional subprofiles */
> +	if (aa_is_nameX(e, AA_LIST, "hats")) {
> +		while (!aa_is_nameX(e, AA_LISTEND, NULL)) {
> +			struct aa_profile *subprofile;
> +			subprofile = aa_unpack_profile(e);
> +			if (IS_ERR(subprofile)) {

What bounds recursion here on invalid input ?


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

* Re: [AppArmor 40/41] AppArmor: all the rest
  2007-04-12  9:08 ` [AppArmor 40/41] AppArmor: all the rest jjohansen
@ 2007-04-12 10:32   ` Al Viro
  2007-04-12 11:32     ` Al Viro
  0 siblings, 1 reply; 187+ messages in thread
From: Al Viro @ 2007-04-12 10:32 UTC (permalink / raw)
  To: jjohansen
  Cc: linux-kernel, linux-security-module, linux-fsdevel, chrisw,
	Andreas Gruenbacher

On Thu, Apr 12, 2007 at 02:08:49AM -0700, jjohansen@suse.de wrote:
> +	} else if (profile1 > profile2) {
> +		/* profile1 cannot be NULL here. */
> +		spin_lock_irqsave(&profile1->lock, profile1->int_flags);
> +		if (profile2)
> +			spin_lock(&profile2->lock);
> +
> +	} else {
> +		/* profile2 cannot be NULL here. */
> +		spin_lock_irqsave(&profile2->lock, profile2->int_flags);
> +		spin_lock(&profile1->lock);
> +	}

Ahem...

profile2 is locked individually.  profile1 > profile2.  profile1 is not
locked.  We try to lock both.  profile1 is locked OK, flags (with interrupts
disabled) are stored into it.  We spin trying to lock profile2.  Eventually,
whoever had held profile2 unlocks it, restoring the flags from profile2.
We happily grab the spinlock and move on.  When we unlock the pair, we
restore flags from profile1.  I.e. we are left with interrupts disabled.

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

* Re: [AppArmor 00/41] AppArmor security module overview
  2007-04-12  9:08 [AppArmor 00/41] AppArmor security module overview jjohansen
                   ` (40 preceding siblings ...)
  2007-04-12  9:08 ` [AppArmor 41/41] Add AppArmor LSM to security/Makefile jjohansen
@ 2007-04-12 10:33 ` Shaya Potter
  2007-04-12 13:50 ` Pavel Machek
  2007-04-13  8:04 ` Rob Meijer
  43 siblings, 0 replies; 187+ messages in thread
From: Shaya Potter @ 2007-04-12 10:33 UTC (permalink / raw)
  To: jjohansen; +Cc: linux-kernel, linux-security-module, linux-fsdevel, chrisw

jjohansen@suse.de wrote:
> This post contains patches to include the AppArmor application security
> framework, with request for inclusion.

question in general, these seems like a fairly invasive series of 
patches.  back when I first started graduate school, I prototyped a 
relatively simple stackable file system on 2.4 that seems to be able to 
do a lot of what app armor does (or at least seems to be easily 
extensible to o everything app armor does) from an fs perspective, 
without having to modify the kernel at all, why not use that approach?

What I did back then was I took Erez Zadok's fist, created his base0fs, 
which basically does nothing, just passes everything directly down.  I 
viewed it as a null stackable fs.  I then modified it to

a) contain a set of rules (be able to add, delete, modify them)

b) fs's private lookup() determines if a dentry matches a rule and tags
it (stored in dentry private data, but inode can be used as well)

c) fs's private permission() checks the rule data stored in private data 
to determine if the generic_permission should be even called.

what I didn't do is mmap or hard link, but those are additional checks 
one can do in those specific f_ops.

Basically, why force the VFS to change, when one can create an 
apparmorfs that stacks on top of whatever fs you want to use app armor 
rules with, create a namespace containing that new stacked fs only (to 
contain processes within the stacked fs).

This approach doesn't suffer from the normal stackable file system 
"issue" since  there should be no complex what I'll call "cache 
coherency" issues due to the stackable "directory entry" namespace being 
the same exact as the underlying namespace and it passing down page 
cache operations directly to the lower fs.  So one could stack on top of 
a file system one is using for both apparmor protected and unprotected 
processes.

I could imagine there might be an issue w/ how one deals with special 
file systems (ala proc and others).  But the way we approached this in 
general, is that this is an aspect of containers. namely, each protected 
area is a container itself, and hence has its own private virtualized 
proc....

my code was mostly prototype level (As well as only for 2.4), but it 
would seem to very easily to duplicate in a production level quailty for 
2.6.

anyways, just a thought

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

* Re: [AppArmor 37/41] AppArmor: Main Part
  2007-04-12  9:08 ` [AppArmor 37/41] AppArmor: Main Part jjohansen
@ 2007-04-12 10:37   ` Alan Cox
  2007-04-13  8:17     ` Andreas Gruenbacher
  2007-04-13  8:48     ` Andreas Gruenbacher
  0 siblings, 2 replies; 187+ messages in thread
From: Alan Cox @ 2007-04-12 10:37 UTC (permalink / raw)
  To: jjohansen
  Cc: linux-kernel, linux-security-module, linux-fsdevel, chrisw,
	John Johansen, Andreas Gruenbacher

> + * aa_taskattr_access
> + * @name: name of the file to check
> + *
> + * Check if name matches /proc/self/attr/current, with self resolved
> + * to the current pid. This file is the usermode iterface for
> + * changing one's hat.
> + */
> +static inline int aa_taskattr_access(const char *name)
> +{
> +	unsigned long pid;
> +	char *end;
> +
> +	if (strncmp(name, "/proc/", 6) != 0)
> +		return 0;

The proc file system may not be mounted at /proc. There are environments
where this is done for good reason (eg not wanting the /proc info exposed
to a low trust environment). Another is when FUSE is providing an
arbitrated proc either by merging across clusters or by removing stuff.

> +static int aa_file_denied(struct aa_profile *profile, const char *name,
> +			  int mask)
> +{
> +	int perms;
> +
> +	/* Always allow write access to /proc/self/attr/current. */
> +	if (mask == MAY_WRITE && aa_taskattr_access(name))
> +		return 0;

Why can't this be done in the profile itself to avoid kernel special case
uglies and inflexibility ?

> +		if (PTR_ERR(sa->name) == -ENOENT && (check & AA_CHECK_FD))
> +			denied_mask = 0;

Now there is an interesting question. Is PTR_ERR() safe for kernel
pointers on all platforms or just for user ones ?



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

* Re: [AppArmor 33/41] Add d_namespace_path() to obtain namespace relative pathnames
  2007-04-12  9:08 ` [AppArmor 33/41] Add d_namespace_path() to obtain namespace relative pathnames jjohansen
@ 2007-04-12 10:49   ` Al Viro
  0 siblings, 0 replies; 187+ messages in thread
From: Al Viro @ 2007-04-12 10:49 UTC (permalink / raw)
  To: jjohansen
  Cc: linux-kernel, linux-security-module, linux-fsdevel, chrisw,
	Andreas Gruenbacher

> +char *d_namespace_path(struct dentry *dentry, struct vfsmount *vfsmnt,
> +		       char *buf, int buflen)
> +{
> +	char *res;
> +	struct vfsmount *rootmnt, *nsrootmnt;
> +	struct dentry *root;
> +
> +	read_lock(&current->fs->lock);
> +	rootmnt = mntget(current->fs->rootmnt);
> +	read_unlock(&current->fs->lock);
> +	spin_lock(&vfsmount_lock);
> +	nsrootmnt = mntget(rootmnt->mnt_ns->root);

... and when somebody does umount -l on your chroot jail, you get
NULL ->mnt_ns.  Oops...

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

* Re: [AppArmor 40/41] AppArmor: all the rest
  2007-04-12 10:32   ` Al Viro
@ 2007-04-12 11:32     ` Al Viro
  0 siblings, 0 replies; 187+ messages in thread
From: Al Viro @ 2007-04-12 11:32 UTC (permalink / raw)
  To: jjohansen
  Cc: linux-kernel, linux-security-module, linux-fsdevel, chrisw,
	Andreas Gruenbacher

On Thu, Apr 12, 2007 at 11:32:00AM +0100, Al Viro wrote:
> On Thu, Apr 12, 2007 at 02:08:49AM -0700, jjohansen@suse.de wrote:
> > +	} else if (profile1 > profile2) {
> > +		/* profile1 cannot be NULL here. */
> > +		spin_lock_irqsave(&profile1->lock, profile1->int_flags);
> > +		if (profile2)
> > +			spin_lock(&profile2->lock);
> > +
> > +	} else {
> > +		/* profile2 cannot be NULL here. */
> > +		spin_lock_irqsave(&profile2->lock, profile2->int_flags);
> > +		spin_lock(&profile1->lock);
> > +	}
> 
> Ahem...
> 
> profile2 is locked individually.  profile1 > profile2.  profile1 is not
> locked.  We try to lock both.  profile1 is locked OK, flags (with interrupts
> disabled) are stored into it.  We spin trying to lock profile2.  Eventually,
> whoever had held profile2 unlocks it, restoring the flags from profile2.
> We happily grab the spinlock and move on.  When we unlock the pair, we
> restore flags from profile1.  I.e. we are left with interrupts disabled.

Please, ignore - shouldn't have posted without coffee...  Flags would be
for different CPUs in that case, obviously.

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

* Re: [AppArmor 39/41] AppArmor: Profile loading and manipulation, pathname matching
  2007-04-12  9:08 ` [AppArmor 39/41] AppArmor: Profile loading and manipulation, pathname matching jjohansen
  2007-04-12 10:28   ` Alan Cox
@ 2007-04-12 13:46   ` Andi Kleen
  2007-04-15 14:21     ` Andreas Gruenbacher
  1 sibling, 1 reply; 187+ messages in thread
From: Andi Kleen @ 2007-04-12 13:46 UTC (permalink / raw)
  To: jjohansen
  Cc: linux-kernel, linux-security-module, linux-fsdevel, chrisw,
	Andreas Gruenbacher

jjohansen@suse.de writes:

[didn't review code fully, just some stuff I noticed]

> +
> +struct aa_dfa {
> +	struct table_header *tables[YYTD_ID_NXT];
> +};

If that is passed in from user space you would need special compat
code for 64bit kernels who support 32bit userland.
Better to avoid pointers.

> +
> +	/* get optional subprofiles */
> +	if (aa_is_nameX(e, AA_LIST, "hats")) {
> +		while (!aa_is_nameX(e, AA_LISTEND, NULL)) {
> +			struct aa_profile *subprofile;
> +			subprofile = aa_unpack_profile(e);

Is there any check that would guard the recursion from stack
overflow on malicious input?  

> +	/*
> +	 * Replacement needs to allocate a new aa_task_context for each
> +	 * task confined by old_profile.  To do this the profile locks
> +	 * are only held when the actual switch is done per task.  While
> +	 * looping to allocate a new aa_task_context the old_task list
> +	 * may get shorter if tasks exit/change their profile but will
> +	 * not get longer as new task will not use old_profile detecting
> +	 * that is stale.
> +	 */
> +	do {
> +		new_cxt = aa_alloc_task_context(GFP_KERNEL | __GFP_NOFAIL);

NOFAIL is usually a bad sign. It should be only used if there is no
alternative.

-Andi


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

* Re: [AppArmor 00/41] AppArmor security module overview
  2007-04-12  9:08 [AppArmor 00/41] AppArmor security module overview jjohansen
                   ` (41 preceding siblings ...)
  2007-04-12 10:33 ` [AppArmor 00/41] AppArmor security module overview Shaya Potter
@ 2007-04-12 13:50 ` Pavel Machek
  2007-04-12 21:13   ` David Wagner
  2007-04-13  8:04 ` Rob Meijer
  43 siblings, 1 reply; 187+ messages in thread
From: Pavel Machek @ 2007-04-12 13:50 UTC (permalink / raw)
  To: jjohansen; +Cc: linux-kernel, linux-security-module, linux-fsdevel, chrisw

Hi!

> AppArmor's Overall Design
> =========================
> 
> AppArmor protects systems from vulnerable software by confining
> processes, giving them "least privilege" access to the system's
> resources: with least privilege, processes are allowed exactly what they
> need, nothing more, and nothing less. Systems are thus protected from
> bugs in applications that would lead to privilege escalation, such as
> remote system access because of a buffer overflow in a web server, etc.
> 
> AppArmor does this by defining application profiles which list allowed
> accesses, and assigning those profiles to processes. AppArmor does *not*

You can do the same with ptrace. If that's not fast enough... improve
ptrace?

> The corollary to this is that attacks against AppArmor that start with
> "assume some unconfined process does ..." are outside the AppArmor
> threat model. Any process that might do something malicious to an

IOW AppArmor is broken by design. (One reason is: operations by unconfined
processes that did not use to be security sensitive before -- ln
shadow random_name -- are security sensitive now.)

							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] 187+ messages in thread

* Re: [AppArmor 00/41] AppArmor security module overview
  2007-04-12 13:50 ` Pavel Machek
@ 2007-04-12 21:13   ` David Wagner
  2007-04-16  7:46     ` Pavel Machek
  0 siblings, 1 reply; 187+ messages in thread
From: David Wagner @ 2007-04-12 21:13 UTC (permalink / raw)
  To: linux-kernel

Pavel Machek  wrote:
>You can do the same with ptrace. If that's not fast enough... improve
>ptrace?

I did my Master's thesis on a system called Janus that tried using ptrace
for this goal.  The bottom line is that ptrace sucks for this purpose.
It is a kludge.  It is not the right approach.  I do not know of any
satisfactory way to improve ptrace for this purpose; you have to throw
away ptrace and start over.

At the time I did the work, ptrace has all sorts of serious problems.
Here are some of them.  There was no way to follow fork securely.
There was no way to deny a single system call without killing the process
entirely.  Performance was poor, because ptrace context-switches on every
read() and write().  Handling of signals is a mess: ptrace overloads the
signal mechanism to deliver its events, which in retrospect was a lousy
design decision it makes the tracer complex and error-prone and makes
it hard to maintain the transparency of tracing.  ptrace breaks wait(),
and consequently handling wait() and other signal-related system calls
transparently and securely is ugly at best.  Handling signals is probably
feasible but a total mess, and that's the last thing you want in the
security-critical part of your system.  In addition, ptrace operates
at the wrong level of abstraction and forces the user-level tracer to
maintain a lot of shadow state that must be kept in sync with state held
by the kernel.  That's an opportunity for security holes.  Also, ptrace
has no way to force the tracee to die if the tracer unexpectedly dies,
which is risky when using ptrace for security confinement.  I haven't
checked whether these problems are still present in the current
implementation of ptrace, but I'd guess that many probably still are,
because many are fundamental consequences of how ptrace works.

Before advocating ptrace for this purpose, I encourage you to study some
of the relevant literature.  Start with Chapter 4 of my Master's thesis.
  http://www.cs.berkeley.edu/~daw/papers/janus-masters.ps
Then, read Tal Garfinkel's paper on system call interposition.
  http://www.stanford.edu/~talg/papers/traps/abstract.html
Then, read about Ostia.
  http://www.stanford.edu/~talg/papers/NDSS04/abstract.html
I think these may change your mind about the suitability of ptrace for
this task.

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

* Re: [AppArmor 00/41] AppArmor security module overview
  2007-04-12  9:08 [AppArmor 00/41] AppArmor security module overview jjohansen
                   ` (42 preceding siblings ...)
  2007-04-12 13:50 ` Pavel Machek
@ 2007-04-13  8:04 ` Rob Meijer
  43 siblings, 0 replies; 187+ messages in thread
From: Rob Meijer @ 2007-04-13  8:04 UTC (permalink / raw)
  To: jjohansen; +Cc: linux-kernel, linux-security-module, linux-fsdevel, chrisw

I've posted on the subject before, and as noone seemed to truely relate
to the concept I concequently dropped my effords, but as you seem to be half
a step in the general right direction, this may be a good time to bring
it up again.

If instead of 'least privilege' and fat profiles, you would opt for 'least
authority' and (potentialy) thin profiles, this would make the whole also
usable for systems initialy designed with security in mind.
To accomplish such a thing I proposed that the non 'at' family of calls
for filesystems should be considdered to be priviledged operations (within
a least authority context), and the 'at' family of operations should have
invocations with uptree path tokens also be considdered priviledged
(within a least authority context). The non uptree invocations of the 'at'
family
should be considdered unpriviledged, and should thus always be allowed
seperately from any profile.

With this distinction implemented, you could than potentialy use thin
profiles and dynamicly exchange authority by passing along directory
file handles when needed.

Where with the 'least priviledge' approach the profile would need to grant
the each priviledge the application might need, but when you would be able
to use both file handles, socket handles and directory handles as tokens
of authorization that can be comunicated seperately and freely, without
being stopped from being used by least priviledge profiles, the profiles
needed will start out much thiner, and will dynamicly expand to just a
limited subset of the fat least priviledge profile.

I believe that being able to be able to distinguish between the
the least authority (no uptree) usage of open file/dir/socket handles and
other operations is essential. If a profile blocks a program from using
these open file/dir/socket handles in a way not violating least authority
(that is no uptree tokens in at family calls), this would be a major
design flaw.

Rob


On Thu, April 12, 2007 11:08, jjohansen@suse.de wrote:

> AppArmor's Overall Design
> =========================
>
> AppArmor protects systems from vulnerable software by confining
> processes, giving them "least privilege" access to the system's
> resources: with least privilege, processes are allowed exactly what they
> need, nothing more, and nothing less. Systems are thus protected from
> bugs in applications that would lead to privilege escalation, such as
> remote system access because of a buffer overflow in a web server, etc.
>
> AppArmor does this by defining application profiles which list allowed
> accesses, and assigning those profiles to processes. AppArmor does *not*
> require the user to confine all processes on the system.  Rather, you
> need to provide AppArmor profiles for every process that is potentially
> subject to manipulation by the attacker. For instance, to defend against
> network attack, confine all process that access the network.
>
> The corollary to this is that attacks against AppArmor that start with
> "assume some unconfined process does ..." are outside the AppArmor
> threat model. Any process that might do something malicious to an
> AppArmor system should be confined by an AppArmor profile.
>
> The kernel manages many different kinds of resources.  AppArmor
> currently controls access to two key resources among them: files, and
> POSIX Capabilities.  (Additional protection for things like rlimits,
> interprocess communication, and network access are being worked on, and
> are expected to become available in a future version.)
>
>
> File Access Control
> -------------------
>
> Application profiles control file access by pathname: each profile
> contains a list of fully qualified pathnames (potentially containing
> globbing) and associated access modes: read (r), write (w), different
> kinds of execute (ix, Px, px, Ux, ux), create hard-link (l), and memory
> map for execution (m).
>
> For example, the following two rules permit read access to any file
> below /srv/www/htdocs/**.html, and memory map for execution (m), execute
> inheriting the current profile (ix), and read (r) access to
> /usr/sbin/suexec2:
>
>     /srv/www/htdocs/**.html r,
>     /usr/sbin/suexec2 mixr,



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

* Re: [AppArmor 37/41] AppArmor: Main Part
  2007-04-12 10:37   ` Alan Cox
@ 2007-04-13  8:17     ` Andreas Gruenbacher
  2007-04-13  8:48     ` Andreas Gruenbacher
  1 sibling, 0 replies; 187+ messages in thread
From: Andreas Gruenbacher @ 2007-04-13  8:17 UTC (permalink / raw)
  To: Alan Cox
  Cc: jjohansen, linux-kernel, linux-security-module, linux-fsdevel, chrisw

On Thursday 12 April 2007 12:37, Alan Cox wrote:
> The proc file system may not be mounted at /proc. There are environments
> where this is done for good reason (eg not wanting the /proc info exposed
> to a low trust environment). Another is when FUSE is providing an
> arbitrated proc either by merging across clusters or by removing stuff.
> [...]
> Why can't this be done in the profile itself to avoid kernel special case
> uglies and inflexibility ?

Good points. I'm in fact not sure how this could have been missed, and indeed 
it makes more sense to put this in profiles.

Thanks,
Andreas

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

* Re: [AppArmor 37/41] AppArmor: Main Part
  2007-04-12 10:37   ` Alan Cox
  2007-04-13  8:17     ` Andreas Gruenbacher
@ 2007-04-13  8:48     ` Andreas Gruenbacher
  2007-04-13  8:52       ` Nick Piggin
  1 sibling, 1 reply; 187+ messages in thread
From: Andreas Gruenbacher @ 2007-04-13  8:48 UTC (permalink / raw)
  To: Alan Cox
  Cc: jjohansen, linux-kernel, linux-security-module, linux-fsdevel, chrisw

On Thursday 12 April 2007 12:37, Alan Cox wrote:
> > +		if (PTR_ERR(sa->name) == -ENOENT && (check & AA_CHECK_FD))
> > +			denied_mask = 0;
>
> Now there is an interesting question. Is PTR_ERR() safe for kernel
> pointers on all platforms or just for user ones ?

It's used for kernel pointers all over the place and mmap also mixes user 
addresses with -Exxx, so it's definitely supposed to work. I'm not sure how 
exactly the topmost page is kept from getting mapped.

Andreas

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

* Re: [AppArmor 37/41] AppArmor: Main Part
  2007-04-13  8:48     ` Andreas Gruenbacher
@ 2007-04-13  8:52       ` Nick Piggin
  0 siblings, 0 replies; 187+ messages in thread
From: Nick Piggin @ 2007-04-13  8:52 UTC (permalink / raw)
  To: Andreas Gruenbacher
  Cc: Alan Cox, jjohansen, linux-kernel, linux-security-module,
	linux-fsdevel, chrisw

Andreas Gruenbacher wrote:
> On Thursday 12 April 2007 12:37, Alan Cox wrote:
> 
>>>+		if (PTR_ERR(sa->name) == -ENOENT && (check & AA_CHECK_FD))
>>>+			denied_mask = 0;
>>
>>Now there is an interesting question. Is PTR_ERR() safe for kernel
>>pointers on all platforms or just for user ones ?
> 
> 
> It's used for kernel pointers all over the place and mmap also mixes user 
> addresses with -Exxx, so it's definitely supposed to work. I'm not sure how 
> exactly the topmost page is kept from getting mapped.

Yeah, the comments indicate it was first used for dentries.

I wonder if it shouldn't be using the NULL page instead? (ie 0-4095)

-- 
SUSE Labs, Novell Inc.

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

* Re: [AppArmor 39/41] AppArmor: Profile loading and manipulation, pathname matching
  2007-04-12 13:46   ` Andi Kleen
@ 2007-04-15 14:21     ` Andreas Gruenbacher
  2007-04-16  6:27       ` Andi Kleen
                         ` (2 more replies)
  0 siblings, 3 replies; 187+ messages in thread
From: Andreas Gruenbacher @ 2007-04-15 14:21 UTC (permalink / raw)
  To: Andi Kleen
  Cc: jjohansen, linux-kernel, linux-security-module, linux-fsdevel, chrisw

On Thursday 12 April 2007 15:46, Andi Kleen wrote:
> > +struct aa_dfa {
> > +	struct table_header *tables[YYTD_ID_NXT];
> > +};
> 
> If that is passed in from user space you would need special compat
> code for 64bit kernels who support 32bit userland.
> Better to avoid pointers.

This struct is not passed between the kernel and user space; no problem here. 
In fact the profiles format used is fully machine independent.

> > +
> > +	/* get optional subprofiles */
> > +	if (aa_is_nameX(e, AA_LIST, "hats")) {
> > +		while (!aa_is_nameX(e, AA_LISTEND, NULL)) {
> > +			struct aa_profile *subprofile;
> > +			subprofile = aa_unpack_profile(e);
> 
> Is there any check that would guard the recursion from stack
> overflow on malicious input?  

It's nice to check for consistency though, so we're adding that. Profile 
loading is a trusted operation, at least so far, and so security wise we 
don't actually have to care --- if loading an invalid profile can bring down 
the system, then that's no worse than an arbitrary module that crashes the 
machine. Not sure if there will ever be user loadable profiles; at least at 
that point we had to care.

> > +	/*
> > +	 * Replacement needs to allocate a new aa_task_context for each
> > +	 * task confined by old_profile.  To do this the profile locks
> > +	 * are only held when the actual switch is done per task.  While
> > +	 * looping to allocate a new aa_task_context the old_task list
> > +	 * may get shorter if tasks exit/change their profile but will
> > +	 * not get longer as new task will not use old_profile detecting
> > +	 * that is stale.
> > +	 */
> > +	do {
> > +		new_cxt = aa_alloc_task_context(GFP_KERNEL | __GFP_NOFAIL);
> 
> NOFAIL is usually a bad sign. It should be only used if there is no
> alternative.

At this point there is no secure alternative to allocating a task context --- 
except killing the task, maybe.

Thanks,
Andreas

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

* Re: [AppArmor 31/41] Fix __d_path() for lazy unmounts and make it unambiguous; exclude unreachable mount points from /proc/mounts
  2007-04-12  9:58   ` Alan Cox
@ 2007-04-15 17:40     ` Andreas Gruenbacher
  2007-04-16 21:57       ` Alan Cox
  0 siblings, 1 reply; 187+ messages in thread
From: Andreas Gruenbacher @ 2007-04-15 17:40 UTC (permalink / raw)
  To: Alan Cox
  Cc: jjohansen, linux-kernel, linux-security-module, linux-fsdevel,
	chrisw, Andrew Morton

On Thursday 12 April 2007 11:58, Alan Cox wrote:
> > Third, sys_getcwd() shouldn't return disconnected paths.  The patch checks 
for
> > that, and makes it fail with -ENOENT in that case
> 
> That is a fairly significant and sudden change to the existing
> kernel/user interface.

Well, this is not meant for 2.6.21. I hope it is possible to change it in 
early 2.6.22; otherwise if we can't fix mistakes from the past we are pretty 
doomed.

The problem with unreachable paths is that they are meaningless to the 
process -- the unreachable path does not really work as a path anymore, it 
could at best serve some informational value -- at worst it could lead to 
hard to track down misbehavior. ENOENT is a documented error code for 
``directory has been unlinked''. The man page does not mention unreachable 
paths, but the documentation can easily be changed.

What's an unreachable path to one process may be a reachable path for another, 
or may not be reachable at all (such as the rootfs).

> > Fourth, this now allows us to tell unreachable mount points from reachable
> > ones when generating the /proc/mounts and /proc/$pid/mountstats files. 
> > Unreachable mount points are not interesting to processes (they can't get
> > there, anyway), so we hide unreachable mounts.  In particular, ordinary
> 
> This is untrue. The process can get there (via fd passing with another
> task)

Process can access file descriptors which are unreachable via path name just 
fine indeed, but those fds still don't have a valid path in the context of 
that process.

Mount points in /proc/mounts as well as paths returned by getcwd() are 
relative to the chroot of the querying process, and listing a mount point 
that is unreachable by that process just doesn't help anybody -- that 
particular process cannot do anything with them anyway.

> and the process can be producing output for the human operators, who most
> definitely need to know and see this stuff.

We are only talking about mount points unreachable by a particular process; 
this does not mean that the mount point isn't reachable by other processes. 
Human operators can choose the context from which they are looking 
at /proc/mounts. If they are looking form the "real" root, the will see all 
mounts that any process can reach (in that namespace).

The rootfs is an example of a mount point that is not reachable by any process 
(after the initrd init process): listing it in /proc/mounts is totally 
pointless, for example -- the rootfs has no meaning to any of those 
processes. (From the point of view of the initrd init process the rootfs is 
reachable of course, and so it also shows up in /proc/mounts.) 

Another context in which the current /proc/mounts doesn't make sense is chroot 
environments: right now if you have proc mounted on /proc as usual as well as 
in a chroot, from the point of view of the "real" root, /proc/mounts will 
contain something like this (omitting all other mounts):

	proc /proc proc rw 0 0
	proc /chroot/proc proc rw 0 0

>From the point of view of the chroot, we get:

	proc /proc proc rw 0 0
	proc /proc proc rw 0 0

So there is no way to tell what's really mounted where (and how) from within 
the chroot. That's really quite broken.

Now it would be possible to use some other syntax to disambiguate unreachable 
mounts in /proc/mounts, like letting such paths start with "//", or removing 
leading slashes in those cases. At least removing leading slashes is quite 
likely to break applications though, and such a hack wouldn't really help 
anybody.

Whatever syntax we could come up with, those paths would be meaningless in the 
given context. They may be meaningful in other context -- exactly if the 
paths are reachable.

> I don't think this is fit to apply in current form. The hiding of mounts
> and mountstats is the wrong approach. The changes to getcwd behaviour
> bother me too as we are changing user space behaviour without warning.

Which kind of warning do you have in mind?

Thanks,
Andreas

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

* Re: [AppArmor 39/41] AppArmor: Profile loading and manipulation, pathname matching
  2007-04-15 14:21     ` Andreas Gruenbacher
@ 2007-04-16  6:27       ` Andi Kleen
  2007-04-16 20:56         ` John Johansen
  2007-04-16  7:39       ` Pavel Machek
  2007-04-16 22:00       ` Alan Cox
  2 siblings, 1 reply; 187+ messages in thread
From: Andi Kleen @ 2007-04-16  6:27 UTC (permalink / raw)
  To: Andreas Gruenbacher
  Cc: Andi Kleen, jjohansen, linux-kernel, linux-security-module,
	linux-fsdevel, chrisw

> It's nice to check for consistency though, so we're adding that. Profile 
> loading is a trusted operation, at least so far, and so security wise we 
> don't actually have to care --- if loading an invalid profile can bring down 
> the system, then that's no worse than an arbitrary module that crashes the 
> machine. Not sure if there will ever be user loadable profiles; at least at 
> that point we had to care.

A security system that allows to crash the kernel is a little weird 
though. It would be better to check. Not that a recursion check
is particularly expensive.

-Andi

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

* Re: [AppArmor 39/41] AppArmor: Profile loading and manipulation, pathname matching
  2007-04-15 14:21     ` Andreas Gruenbacher
  2007-04-16  6:27       ` Andi Kleen
@ 2007-04-16  7:39       ` Pavel Machek
  2007-04-16 22:00       ` Alan Cox
  2 siblings, 0 replies; 187+ messages in thread
From: Pavel Machek @ 2007-04-16  7:39 UTC (permalink / raw)
  To: Andreas Gruenbacher
  Cc: Andi Kleen, jjohansen, linux-kernel, linux-security-module,
	linux-fsdevel, chrisw

Hi!

> > > +
> > > +	/* get optional subprofiles */
> > > +	if (aa_is_nameX(e, AA_LIST, "hats")) {
> > > +		while (!aa_is_nameX(e, AA_LISTEND, NULL)) {
> > > +			struct aa_profile *subprofile;
> > > +			subprofile = aa_unpack_profile(e);
> > 
> > Is there any check that would guard the recursion from stack
> > overflow on malicious input?  
> 
> It's nice to check for consistency though, so we're adding that. Profile 
> loading is a trusted operation, at least so far, and so security wise we 
> don't actually have to care --- if loading an invalid profile can bring down 
> the system, then that's no worse than an arbitrary module that crashes the 
> machine. Not sure if there will ever be user loadable profiles; at least at 
> that point we had to care.

It is not a _security_ problem, but face it, mount("/very weird
filename") is not expected to crash the kernel, either. It is
quality-of-impelmentation problem.

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

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

* Re: [AppArmor 00/41] AppArmor security module overview
  2007-04-12 21:13   ` David Wagner
@ 2007-04-16  7:46     ` Pavel Machek
  2007-04-16 18:24       ` David Wagner
  0 siblings, 1 reply; 187+ messages in thread
From: Pavel Machek @ 2007-04-16  7:46 UTC (permalink / raw)
  To: David Wagner; +Cc: linux-kernel

Hi!

> >You can do the same with ptrace. If that's not fast enough... improve
> >ptrace?
> 
> I did my Master's thesis on a system called Janus that tried using ptrace
> for this goal.  The bottom line is that ptrace sucks for this purpose.
> It is a kludge.  It is not the right approach.  I do not know of any
> satisfactory way to improve ptrace for this purpose; you have to throw
> away ptrace and start over.
> 
> At the time I did the work, ptrace has all sorts of serious problems.
> Here are some of them.  There was no way to follow fork securely.

Actually there is now. I did something similar called subterfugue and
we solved this one.

> There was no way to deny a single system call without killing the process
> entirely.  Performance was poor, because ptrace context-switches on
> every
> read() and write().

You can't deny a system call, but you can turn it into getpid(), then
fake the return value. You probably could invent ptrace extensions,
like solaris did, to avoid context switches.

>  Handling of signals is a mess: ptrace overloads the
> signal mechanism to deliver its events, which in retrospect was a lousy
> design decision it makes the tracer complex and error-prone and makes
> it hard to maintain the transparency of tracing.  ptrace breaks wait(),
> and consequently handling wait() and other signal-related system calls
> transparently and securely is ugly at best

We got this solved in linux, I believe.

> .  Handling signals is probably
> feasible but a total mess, and that's the last thing you want in the
> security-critical part of your system.  In addition, ptrace operates
> at the wrong level of abstraction and forces the user-level tracer to
> maintain a lot of shadow state that must be kept in sync with state held
> by the kernel.  That's an opportunity for security holes.  Also, ptrace
> has no way to force the tracee to die if the tracer unexpectedly dies,
> which is risky when using ptrace for security confinement.  

I think we actually have a flag for "kill this if tracer dies"... or
we could add it.

> I haven't
> checked whether these problems are still present in the current
> implementation of ptrace, but I'd guess that many probably still are,
> because many are fundamental consequences of how ptrace works.
> 
> Before advocating ptrace for this purpose, I encourage you to study some
> of the relevant literature.  Start with Chapter 4 of my Master's
> thesis.

I'm not advocating it. I've done this before, see subterfugue.org. It
was a ugly hack, mostly because it was filename based. Unfortunately
AA is also filename-based.
									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] 187+ messages in thread

* [nameidata 1/2] Don't pass NULL nameidata to vfs_create
  2007-04-12 10:06   ` Christoph Hellwig
@ 2007-04-16 16:11     ` Andreas Gruenbacher
  2007-04-16 16:21       ` Christoph Hellwig
  2007-04-16 16:25       ` Matthew Wilcox
  2007-04-16 16:29     ` [nameidata 2/2] Pass no useless nameidata to the create, lookup, and permission IOPs Andreas Gruenbacher
  1 sibling, 2 replies; 187+ messages in thread
From: Andreas Gruenbacher @ 2007-04-16 16:11 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: jjohansen, linux-kernel, linux-security-module, linux-fsdevel,
	chrisw, Tony Jones

On Thursday 12 April 2007 12:06, Christoph Hellwig wrote:
> Once again very strong NACK.  Every conditional passing of vfsmounts get my
> veto.  As mentioned last time if you really want this send a patch series
> first that passed the vfsmount consistantly.

I don't consider it fair to NACK this patch just because some other part of 
the kernel uses vfs_create() in the wrong way -- those are really independent 
issues. The bug is not that hard to fix though; here is a proposed patch on 
top of the other AppArmor patches.

The offenders are nfsd and the mqueue filesystem. Instantiate a struct 
nameidata there.

The .dentry and .mnt fields can easily be filled in in nfsd. The mqueue 
filesystem is somewhat special: files that mq_open creates are on an internal 
mount and the mqueue filesystem is not generally visible (it may or may not 
be mounted). When passing a regular vfsmount to vfs_create the files would 
appear disconnected while they actually are kernel-internal objects. Use a 
NULL vfsmount there to avoid that -- passing the kernel-internal vfsmount 
there wouldn't help, anyway.

Signed-off-by: Andreas Gruenbacher <agruen@suse.de>

---
 fs/namei.c    |    7 ++++---
 fs/nfsd/vfs.c |   23 +++++++++++++++++++----
 ipc/mqueue.c  |    6 +++++-
 3 files changed, 28 insertions(+), 8 deletions(-)

--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1503,7 +1503,7 @@ int vfs_create(struct inode *dir, struct
 		return -EACCES;	/* shouldn't it be ENOSYS? */
 	mode &= S_IALLUGO;
 	mode |= S_IFREG;
-	error = security_inode_create(dir, dentry, nd ? nd->mnt : NULL, mode);
+	error = security_inode_create(dir, dentry, nd->mnt, mode);
 	if (error)
 		return error;
 	DQUOT_INIT(dir);
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -1108,6 +1108,18 @@ nfsd_commit(struct svc_rqst *rqstp, stru
 }
 #endif /* CONFIG_NFSD_V3 */
 
+static inline int
+nfsd_do_create(struct inode *dir, struct dentry *child, struct vfsmount *mnt,
+	       int mode)
+{
+	struct nameidata nd = {
+		.dentry = child,
+		.mnt = mnt,
+	};
+
+	return vfs_create(dir, child, mode, &nd);
+}
+
 /*
  * Create a file (regular, directory, device, fifo); UNIX sockets 
  * not yet implemented.
@@ -1192,7 +1204,8 @@ nfsd_create(struct svc_rqst *rqstp, stru
 	err = 0;
 	switch (type) {
 	case S_IFREG:
-		host_err = vfs_create(dirp, dchild, iap->ia_mode, NULL);
+		host_err = nfsd_do_create(dirp, dchild, exp->ex_mnt,
+					  iap->ia_mode);
 		break;
 	case S_IFDIR:
 		host_err = vfs_mkdir(dirp, dchild, exp->ex_mnt, iap->ia_mode);
@@ -1253,6 +1266,7 @@ nfsd_create_v3(struct svc_rqst *rqstp, s
 	        int *truncp, int *created)
 {
 	struct dentry	*dentry, *dchild = NULL;
+	struct svc_export *exp;
 	struct inode	*dirp;
 	__be32		err;
 	int		host_err;
@@ -1271,6 +1285,7 @@ nfsd_create_v3(struct svc_rqst *rqstp, s
 		goto out;
 
 	dentry = fhp->fh_dentry;
+	exp = fhp->fh_export;
 	dirp = dentry->d_inode;
 
 	/* Get all the sanity checks out of the way before
@@ -1288,7 +1303,7 @@ nfsd_create_v3(struct svc_rqst *rqstp, s
 	if (IS_ERR(dchild))
 		goto out_nfserr;
 
-	err = fh_compose(resfhp, fhp->fh_export, dchild, fhp);
+	err = fh_compose(resfhp, exp, dchild, fhp);
 	if (err)
 		goto out;
 
@@ -1334,13 +1349,13 @@ nfsd_create_v3(struct svc_rqst *rqstp, s
 		goto out;
 	}
 
-	host_err = vfs_create(dirp, dchild, iap->ia_mode, NULL);
+	host_err = nfsd_do_create(dirp, dchild, exp->ex_mnt, iap->ia_mode);
 	if (host_err < 0)
 		goto out_nfserr;
 	if (created)
 		*created = 1;
 
-	if (EX_ISSYNC(fhp->fh_export)) {
+	if (EX_ISSYNC(exp)) {
 		err = nfserrno(nfsd_sync_dir(dentry));
 		/* setattr will sync the child (or not) */
 	}
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -604,6 +604,10 @@ static int mq_attr_ok(struct mq_attr *at
 static struct file *do_create(struct dentry *dir, struct dentry *dentry,
 			int oflag, mode_t mode, struct mq_attr __user *u_attr)
 {
+	struct nameidata nd = {
+		.dentry = dentry,
+		/* Not a regular create, so set .mnt to NULL. */
+	};
 	struct mq_attr attr;
 	int ret;
 
@@ -619,7 +623,7 @@ static struct file *do_create(struct den
 	}
 
 	mode &= ~current->fs->umask;
-	ret = vfs_create(dir->d_inode, dentry, mode, NULL);
+	ret = vfs_create(dir->d_inode, dentry, mode, &nd);
 	dentry->d_fsdata = NULL;
 	if (ret)
 		goto out;

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

* Re: [nameidata 1/2] Don't pass NULL nameidata to vfs_create
  2007-04-16 16:11     ` [nameidata 1/2] Don't pass NULL nameidata to vfs_create Andreas Gruenbacher
@ 2007-04-16 16:21       ` Christoph Hellwig
  2007-04-16 16:40         ` Andreas Gruenbacher
  2007-05-11 15:59         ` Andreas Gruenbacher
  2007-04-16 16:25       ` Matthew Wilcox
  1 sibling, 2 replies; 187+ messages in thread
From: Christoph Hellwig @ 2007-04-16 16:21 UTC (permalink / raw)
  To: Andreas Gruenbacher
  Cc: Christoph Hellwig, jjohansen, linux-kernel,
	linux-security-module, linux-fsdevel, chrisw, Tony Jones

On Mon, Apr 16, 2007 at 06:11:30PM +0200, Andreas Gruenbacher wrote:
> On Thursday 12 April 2007 12:06, Christoph Hellwig wrote:
> > Once again very strong NACK.  Every conditional passing of vfsmounts get my
> > veto.  As mentioned last time if you really want this send a patch series
> > first that passed the vfsmount consistantly.
> 
> I don't consider it fair to NACK this patch just because some other part of 
> the kernel uses vfs_create() in the wrong way -- those are really independent 
> issues. The bug is not that hard to fix though; here is a proposed patch on 
> top of the other AppArmor patches.

Note that it's not just this particular hunk, all these kinds of conditional
passing are wrong.

> 
> The offenders are nfsd and the mqueue filesystem. Instantiate a struct 
> nameidata there.
> 
> The .dentry and .mnt fields can easily be filled in in nfsd. The mqueue 
> filesystem is somewhat special: files that mq_open creates are on an internal 
> mount and the mqueue filesystem is not generally visible (it may or may not 
> be mounted). When passing a regular vfsmount to vfs_create the files would 
> appear disconnected while they actually are kernel-internal objects. Use a 
> NULL vfsmount there to avoid that -- passing the kernel-internal vfsmount 
> there wouldn't help, anyway.

But anyway, creating fake nameidata structures is not really helpful.
If there is a nameidata passed people expect it to be complete, and
if you pass them to an LSM people will e.g. try to look into lookup
intents.  But similar to the per-mountpoint r/o work I suspect you're
simply operating on the wrong level, but then again this might not
be fixable due to the braindead apparmor design.

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

* Re: [nameidata 1/2] Don't pass NULL nameidata to vfs_create
  2007-04-16 16:11     ` [nameidata 1/2] Don't pass NULL nameidata to vfs_create Andreas Gruenbacher
  2007-04-16 16:21       ` Christoph Hellwig
@ 2007-04-16 16:25       ` Matthew Wilcox
  1 sibling, 0 replies; 187+ messages in thread
From: Matthew Wilcox @ 2007-04-16 16:25 UTC (permalink / raw)
  To: Andreas Gruenbacher
  Cc: Christoph Hellwig, jjohansen, linux-kernel,
	linux-security-module, linux-fsdevel, chrisw, Tony Jones

On Mon, Apr 16, 2007 at 06:11:30PM +0200, Andreas Gruenbacher wrote:
> +static inline int
> +nfsd_do_create(struct inode *dir, struct dentry *child, struct vfsmount *mnt,
> +	       int mode)
> +{
> +	struct nameidata nd = {
> +		.dentry = child,
> +		.mnt = mnt,
> +	};
> +
> +	return vfs_create(dir, child, mode, &nd);
> +}
> +

Wouldn't it normally result in fewer instructions (on most architectures
... maybe not x86) to keep the same argument order as vfs_create?  ie:

static inline int nfsd_do_create(struct inode *dir, struct dentry *child,
				 int mode, struct vfsmount *mnt)


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

* [nameidata 2/2] Pass no useless nameidata to the create, lookup, and permission IOPs
  2007-04-12 10:06   ` Christoph Hellwig
  2007-04-16 16:11     ` [nameidata 1/2] Don't pass NULL nameidata to vfs_create Andreas Gruenbacher
@ 2007-04-16 16:29     ` Andreas Gruenbacher
  2007-04-16 16:39       ` Christoph Hellwig
  2007-04-16 16:42       ` Randy Dunlap
  1 sibling, 2 replies; 187+ messages in thread
From: Andreas Gruenbacher @ 2007-04-16 16:29 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: jjohansen, linux-kernel, linux-security-module, linux-fsdevel,
	chrisw, Tony Jones

Here is a patch with request for comment.

The create, lookup, and permission inode operations are all passed a full
nameidata.  This is unfortunate because in nfsd and the mqueue filesystem we
must instantiate a struct nameidata, but cannot provide all of the same
information of a regular lookup.  The unused fields take up space on the
stack, but more importantly, it is not obvious which fields have meaningful
values and which don't, and so things might easily break.

This patch introduces struct nameidata2 with only the fields that make sense
independent of an actual lookup, and uses that struct in those places where a
full nameidata is not needed.

The entire patch is a little big so I'm only including the key parts here. The
complete version is here:

 http://forgeftp.novell.com/apparmor/LKML_Submission-April_07/split-up-nameidata.diff

Signed-off-by: Andreas Gruenbacher <agruen@suse.de>

--- a/include/linux/namei.h
+++ b/include/linux/namei.h
@@ -14,21 +14,39 @@ struct open_intent {
 
 enum { MAX_NESTED_LINKS = 8 };
 
+/**
+ * Fields shared between nameidata and nameidata2 -- nameidata2 could
+ * be embedded in nameidata, but then the vfs code would become
+ * cluttered with dereferences.
+ */
+#define __NAMEIDATA2				\
+	struct dentry	*dentry;		\
+	struct vfsmount *mnt;			\
+	unsigned int	flags;			\
+						\
+	union {					\
+		struct open_intent open;	\
+	} intent;
+
 struct nameidata {
-	struct dentry	*dentry;
-	struct vfsmount *mnt;
+	__NAMEIDATA2
 	struct qstr	last;
-	unsigned int	flags;
 	int		last_type;
 	unsigned	depth;
 	char *saved_names[MAX_NESTED_LINKS + 1];
+};
 
-	/* Intent data */
-	union {
-		struct open_intent open;
-	} intent;
+struct nameidata2 {
+	__NAMEIDATA2
 };
 
+#undef __NAMEIDATA2
+
+static inline struct nameidata2 *ND2(struct nameidata *nd)
+{
+	return container_of(&nd->dentry, struct nameidata2, dentry);
+}
+
 struct path {
 	struct vfsmount *mnt;
 	struct dentry *dentry;
@@ -76,10 +94,9 @@ extern void path_release_on_umount(struc
 
 extern int __user_path_lookup_open(const char __user *, unsigned lookup_flags, struct nameidata *nd, int open_flags);
 extern int path_lookup_open(int dfd, const char *name, unsigned lookup_flags, struct nameidata *, int open_flags);
-extern struct file *lookup_instantiate_filp(struct nameidata *nd, struct dentry *dentry,
-		int (*open)(struct inode *, struct file *));
+extern struct file *lookup_instantiate_filp(struct nameidata2 *nd, struct dentry *dentry, int (*open)(struct inode *, struct file *));
 extern struct file *nameidata_to_filp(struct nameidata *nd, int flags);
-extern void release_open_intent(struct nameidata *);
+extern void release_open_intent(struct nameidata2 *);
 
 extern struct dentry * lookup_one_len(const char *, struct dentry *, int);
 
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -225,7 +225,7 @@ int generic_permission(struct inode *ino
 	return -EACCES;
 }
 
-int permission(struct inode *inode, int mask, struct nameidata *nd)
+int permission(struct inode *inode, int mask, struct nameidata2 *nd)
 {
 	umode_t mode = inode->i_mode;
 	int retval, submask;
@@ -278,7 +278,7 @@ int permission(struct inode *inode, int 
  * for filesystem access without changing the "normal" uids which
  * are used for other things.
  */
-int vfs_permission(struct nameidata *nd, int mask)
+int vfs_permission(struct nameidata2 *nd, int mask)
 {
 	return permission(nd->dentry->d_inode, mask, nd);
 }
@@ -366,7 +366,7 @@ void path_release_on_umount(struct namei
  * release_open_intent - free up open intent resources
  * @nd: pointer to nameidata
  */
-void release_open_intent(struct nameidata *nd)
+void release_open_intent(struct nameidata2 *nd)
 {
 	if (nd->intent.open.file->f_path.dentry == NULL)
 		put_filp(nd->intent.open.file);
@@ -377,7 +377,7 @@ void release_open_intent(struct nameidat
 static inline struct dentry *
 do_revalidate(struct dentry *dentry, struct nameidata *nd)
 {
-	int status = dentry->d_op->d_revalidate(dentry, nd);
+	int status = dentry->d_op->d_revalidate(dentry, ND2(nd));
 	if (unlikely(status <= 0)) {
 		/*
 		 * The dentry failed validation.
@@ -455,7 +455,7 @@ static int exec_permission_lite(struct i
 
 	return -EACCES;
 ok:
-	return security_inode_permission(inode, MAY_EXEC, nd);
+	return security_inode_permission(inode, MAY_EXEC, ND2(nd));
 }
 
 /*
@@ -491,7 +491,7 @@ static struct dentry * real_lookup(struc
 		struct dentry * dentry = d_alloc(parent, name);
 		result = ERR_PTR(-ENOMEM);
 		if (dentry) {
-			result = dir->i_op->lookup(dir, dentry, nd);
+			result = dir->i_op->lookup(dir, dentry, ND2(nd));
 			if (result)
 				dput(dentry);
 			else
@@ -832,7 +832,7 @@ static fastcall int __link_path_walk(con
 		nd->flags |= LOOKUP_CONTINUE;
 		err = exec_permission_lite(inode, nd);
 		if (err == -EAGAIN)
-			err = vfs_permission(nd, MAY_EXEC);
+			err = vfs_permission(ND2(nd), MAY_EXEC);
  		if (err)
 			break;
 
@@ -978,7 +978,8 @@ return_reval:
 		    (nd->dentry->d_sb->s_type->fs_flags & FS_REVAL_DOT)) {
 			err = -ESTALE;
 			/* Note: we do not d_invalidate() */
-			if (!nd->dentry->d_op->d_revalidate(nd->dentry, nd))
+			if (!nd->dentry->d_op->d_revalidate(nd->dentry,
+							    ND2(nd)))
 				break;
 		}
 return_base:
@@ -1194,7 +1195,7 @@ static int __path_lookup_intent_open(int
 			path_release(nd);
 		}
 	} else if (err != 0)
-		release_open_intent(nd);
+		release_open_intent(ND2(nd));
 	return err;
 }
 
@@ -1255,7 +1256,7 @@ static struct dentry * __lookup_hash(str
 	int err;
 
 	inode = base->d_inode;
-	err = permission(inode, MAY_EXEC, nd);
+	err = permission(inode, MAY_EXEC, ND2(nd));
 	dentry = ERR_PTR(err);
 	if (err)
 		goto out;
@@ -1277,7 +1278,7 @@ static struct dentry * __lookup_hash(str
 		dentry = ERR_PTR(-ENOMEM);
 		if (!new)
 			goto out;
-		dentry = inode->i_op->lookup(inode, new, nd);
+		dentry = inode->i_op->lookup(inode, new, ND2(nd));
 		if (!dentry)
 			dentry = new;
 		else
@@ -1422,7 +1423,7 @@ static int may_delete(struct inode *dir,
  *  4. We can't do it if dir is immutable (done in permission())
  */
 static inline int may_create(struct inode *dir, struct dentry *child,
-			     struct nameidata *nd)
+			     struct nameidata2 *nd)
 {
 	if (child->d_inode)
 		return -EEXIST;
@@ -1492,7 +1493,7 @@ void unlock_rename(struct dentry *p1, st
 }
 
 int vfs_create(struct inode *dir, struct dentry *dentry, int mode,
-		struct nameidata *nd)
+		struct nameidata2 *nd)
 {
 	int error = may_create(dir, dentry, nd);
 
@@ -1528,7 +1529,7 @@ int may_open(struct nameidata *nd, int a
 	if (S_ISDIR(inode->i_mode) && (flag & FMODE_WRITE))
 		return -EISDIR;
 
-	error = vfs_permission(nd, acc_mode);
+	error = vfs_permission(ND2(nd), acc_mode);
 	if (error)
 		return error;
 
@@ -1601,7 +1602,7 @@ static int open_namei_create(struct name
 
 	if (!IS_POSIXACL(dir->d_inode))
 		mode &= ~current->fs->umask;
-	error = vfs_create(dir->d_inode, path->dentry, mode, nd);
+	error = vfs_create(dir->d_inode, path->dentry, mode, ND2(nd));
 	mutex_unlock(&dir->d_inode->i_mutex);
 	dput(nd->dentry);
 	nd->dentry = path->dentry;
@@ -1734,7 +1735,7 @@ exit_dput:
 	dput_path(&path, nd);
 exit:
 	if (!IS_ERR(nd->intent.open.file))
-		release_open_intent(nd);
+		release_open_intent(ND2(nd));
 	path_release(nd);
 	return error;
 
@@ -1762,7 +1763,7 @@ do_link:
 		 * me so stupid? Anathema to whoever designed this non-sense
 		 * with "intent.open".
 		 */
-		release_open_intent(nd);
+		release_open_intent(ND2(nd));
 		return error;
 	}
 	nd->flags &= ~LOOKUP_PARENT;
@@ -1888,7 +1889,7 @@ asmlinkage long sys_mknodat(int dfd, con
 		switch (mode & S_IFMT) {
 		case 0: case S_IFREG:
 			error = vfs_create(nd.dentry->d_inode, dentry, mode,
-					   &nd);
+					   ND2(&nd));
 			break;
 		case S_IFCHR: case S_IFBLK:
 			error = vfs_mknod(nd.dentry->d_inode, dentry, nd.mnt,
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -289,6 +289,7 @@ extern int dir_notify_enable;
 struct hd_geometry;
 struct iovec;
 struct nameidata;
+struct nameidata2;
 struct kiocb;
 struct pipe_inode_info;
 struct poll_table_struct;
@@ -981,8 +982,8 @@ extern void unlock_super(struct super_bl
 /*
  * VFS helper functions..
  */
-extern int vfs_permission(struct nameidata *, int);
-extern int vfs_create(struct inode *, struct dentry *, int, struct nameidata *);
+extern int vfs_permission(struct nameidata2 *, int);
+extern int vfs_create(struct inode *, struct dentry *, int, struct nameidata2 *);
 extern int vfs_mkdir(struct inode *, struct dentry *, struct vfsmount *, int);
 extern int vfs_mknod(struct inode *, struct dentry *, struct vfsmount *, int, dev_t);
 extern int vfs_symlink(struct inode *, struct dentry *, struct vfsmount *, const char *, int);
@@ -1106,8 +1107,8 @@ struct file_operations {
 };
 
 struct inode_operations {
-	int (*create) (struct inode *,struct dentry *,int, struct nameidata *);
-	struct dentry * (*lookup) (struct inode *,struct dentry *, struct nameidata *);
+	int (*create) (struct inode *,struct dentry *,int, struct nameidata2 *);
+	struct dentry * (*lookup) (struct inode *,struct dentry *, struct nameidata2 *);
 	int (*link) (struct dentry *,struct inode *,struct dentry *);
 	int (*unlink) (struct inode *,struct dentry *);
 	int (*symlink) (struct inode *,struct dentry *,const char *);
@@ -1120,7 +1121,7 @@ struct inode_operations {
 	void * (*follow_link) (struct dentry *, struct nameidata *);
 	void (*put_link) (struct dentry *, struct nameidata *, void *);
 	void (*truncate) (struct inode *);
-	int (*permission) (struct inode *, int, struct nameidata *);
+	int (*permission) (struct inode *, int, struct nameidata2 *);
 	int (*setattr) (struct dentry *, struct iattr *);
 	int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *);
 	int (*setxattr) (struct dentry *, const char *,const void *,size_t,int);
@@ -1616,7 +1617,7 @@ extern int do_remount_sb(struct super_bl
 extern sector_t bmap(struct inode *, sector_t);
 #endif
 extern int notify_change(struct dentry *, struct vfsmount *, struct iattr *);
-extern int permission(struct inode *, int, struct nameidata *);
+extern int permission(struct inode *, int, struct nameidata2 *);
 extern int generic_permission(struct inode *, int,
 		int (*check_acl)(struct inode *, int));
 
@@ -1873,7 +1874,7 @@ extern int simple_prepare_write(struct f
 extern int simple_commit_write(struct file *file, struct page *page,
 				unsigned offset, unsigned to);
 
-extern struct dentry *simple_lookup(struct inode *, struct dentry *, struct nameidata *);
+extern struct dentry *simple_lookup(struct inode *, struct dentry *, struct nameidata2 *);
 extern ssize_t generic_read_dir(struct file *, char __user *, size_t, loff_t *);
 extern const struct file_operations simple_dir_operations;
 extern const struct inode_operations simple_dir_inode_operations;

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

* Re: [nameidata 2/2] Pass no useless nameidata to the create, lookup, and permission IOPs
  2007-04-16 16:29     ` [nameidata 2/2] Pass no useless nameidata to the create, lookup, and permission IOPs Andreas Gruenbacher
@ 2007-04-16 16:39       ` Christoph Hellwig
  2007-04-16 16:42       ` Randy Dunlap
  1 sibling, 0 replies; 187+ messages in thread
From: Christoph Hellwig @ 2007-04-16 16:39 UTC (permalink / raw)
  To: Andreas Gruenbacher
  Cc: Christoph Hellwig, jjohansen, linux-kernel,
	linux-security-module, linux-fsdevel, chrisw, Tony Jones

On Mon, Apr 16, 2007 at 06:29:20PM +0200, Andreas Gruenbacher wrote:
>  enum { MAX_NESTED_LINKS = 8 };
>  
> +/**
> + * Fields shared between nameidata and nameidata2 -- nameidata2 could
> + * be embedded in nameidata, but then the vfs code would become
> + * cluttered with dereferences.

you could use an anonymous struct embedeed in both.

> + */
> +#define __NAMEIDATA2				\
> +	struct dentry	*dentry;		\
> +	struct vfsmount *mnt;			\
> +	unsigned int	flags;			\
> +						\
> +	union {					\
> +		struct open_intent open;	\
> +	} intent;

Or better just pass argument directly.  We really
should only pass down the the dentry and the
intent to the filesystem.  The filesystem has
not business looking at mnt in the operations,
and the relevant bits of flags (mostly whether it's
O_EXCLUSIVE) should be stored in the intent, because
that's the only way it should be used.

Doing it that way also allows to fix some braindead calling conventions
like this one:

> -int permission(struct inode *inode, int mask, struct nameidata *nd)
> +int permission(struct inode *inode, int mask, struct nameidata2 *nd)
>  {
>  	umode_t mode = inode->i_mode;
>  	int retval, submask;
> @@ -278,7 +278,7 @@ int permission(struct inode *inode, int 
>   * for filesystem access without changing the "normal" uids which
>   * are used for other things.
>   */

>  static inline struct dentry *
>  do_revalidate(struct dentry *dentry, struct nameidata *nd)

Or this one.

> -			result = dir->i_op->lookup(dir, dentry, nd);
> +			result = dir->i_op->lookup(dir, dentry, ND2(nd));

or this one.

etc..

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

* Re: [nameidata 1/2] Don't pass NULL nameidata to vfs_create
  2007-04-16 16:21       ` Christoph Hellwig
@ 2007-04-16 16:40         ` Andreas Gruenbacher
  2007-04-16 16:45           ` Christoph Hellwig
  2007-05-11 15:59         ` Andreas Gruenbacher
  1 sibling, 1 reply; 187+ messages in thread
From: Andreas Gruenbacher @ 2007-04-16 16:40 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: jjohansen, linux-kernel, linux-security-module, linux-fsdevel,
	chrisw, Tony Jones

On Monday 16 April 2007 18:21, Christoph Hellwig wrote:
> But anyway, creating fake nameidata structures is not really helpful.
> If there is a nameidata passed people expect it to be complete, and
> if you pass them to an LSM people will e.g. try to look into lookup
> intents.

I don't actually agree with that: when nfsd creates a file, it still is a file 
create no matter where it originates from, and so it does make sense to 
provide the appropriate intent information too. Struct nameidata contains 
other crap only needed during an actual lookup too --- that's a mess, and the 
nameidata2 patch shows one possibility how to deal with it. (It's the 
cleanest approach I could think of right now without cluttering the vfs code 
with insane amounts of dereferences.)

Thanks,
Andreas

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

* Re: [nameidata 2/2] Pass no useless nameidata to the create, lookup, and permission IOPs
  2007-04-16 16:29     ` [nameidata 2/2] Pass no useless nameidata to the create, lookup, and permission IOPs Andreas Gruenbacher
  2007-04-16 16:39       ` Christoph Hellwig
@ 2007-04-16 16:42       ` Randy Dunlap
  2007-04-16 16:44         ` Andreas Gruenbacher
  1 sibling, 1 reply; 187+ messages in thread
From: Randy Dunlap @ 2007-04-16 16:42 UTC (permalink / raw)
  To: Andreas Gruenbacher
  Cc: Christoph Hellwig, jjohansen, linux-kernel,
	linux-security-module, linux-fsdevel, chrisw, Tony Jones

On Mon, 16 Apr 2007 18:29:20 +0200 Andreas Gruenbacher wrote:

> Here is a patch with request for comment.
> 
> --- a/include/linux/namei.h
> +++ b/include/linux/namei.h
> @@ -14,21 +14,39 @@ struct open_intent {
>  
>  enum { MAX_NESTED_LINKS = 8 };
>  
> +/**

Please don't use the kernel-doc begin-marker "/**" when the comment block
isn't in kernel-doc format.

> + * Fields shared between nameidata and nameidata2 -- nameidata2 could
> + * be embedded in nameidata, but then the vfs code would become
> + * cluttered with dereferences.
> + */
> +#define __NAMEIDATA2				\
> +	struct dentry	*dentry;		\
> +	struct vfsmount *mnt;			\
> +	unsigned int	flags;			\
> +						\
> +	union {					\
> +		struct open_intent open;	\
> +	} intent;
> +

---
~Randy
*** Remember to use Documentation/SubmitChecklist when testing your code ***

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

* Re: [nameidata 2/2] Pass no useless nameidata to the create, lookup, and permission IOPs
  2007-04-16 16:42       ` Randy Dunlap
@ 2007-04-16 16:44         ` Andreas Gruenbacher
  2007-04-16 16:50           ` Randy Dunlap
  0 siblings, 1 reply; 187+ messages in thread
From: Andreas Gruenbacher @ 2007-04-16 16:44 UTC (permalink / raw)
  To: Randy Dunlap
  Cc: Christoph Hellwig, jjohansen, linux-kernel,
	linux-security-module, linux-fsdevel, chrisw, Tony Jones

On Monday 16 April 2007 18:42, Randy Dunlap wrote:
> Please don't use the kernel-doc begin-marker "/**" when the comment block
> isn't in kernel-doc format.

Sigh, kernel-doc should improve things, not get in the way ...

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

* Re: [nameidata 1/2] Don't pass NULL nameidata to vfs_create
  2007-04-16 16:40         ` Andreas Gruenbacher
@ 2007-04-16 16:45           ` Christoph Hellwig
  2007-04-17 12:09             ` Andreas Gruenbacher
  0 siblings, 1 reply; 187+ messages in thread
From: Christoph Hellwig @ 2007-04-16 16:45 UTC (permalink / raw)
  To: Andreas Gruenbacher
  Cc: Christoph Hellwig, jjohansen, linux-kernel,
	linux-security-module, linux-fsdevel, chrisw, Tony Jones

On Mon, Apr 16, 2007 at 06:40:41PM +0200, Andreas Gruenbacher wrote:
> On Monday 16 April 2007 18:21, Christoph Hellwig wrote:
> > But anyway, creating fake nameidata structures is not really helpful.
> > If there is a nameidata passed people expect it to be complete, and
> > if you pass them to an LSM people will e.g. try to look into lookup
> > intents.
> 
> I don't actually agree with that: when nfsd creates a file, it still is a file 
> create no matter where it originates from, and so it does make sense to 
> provide the appropriate intent information too. Struct nameidata contains 
> other crap only needed during an actual lookup too --- that's a mess, and the 

You should provide intent information, yes - which your patch didn't :)

And yes, I didn't like doing the ugly intent in nameidata hack, it's
creating loads of problems for various parties, e.g. the stackable
filesystem folks.  Now the basic intent in nameidata mistaken has been
made even worse by passing back a struct file in it conditionally and
doing lots of work in ->lookup that shouldn't be there.  (Which btw,
I expect to cause quite a few problems for apparmor or other lsms,
but I guess so far no one has tried them on NFSv4)


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

* Re: [nameidata 2/2] Pass no useless nameidata to the create, lookup, and permission IOPs
  2007-04-16 16:44         ` Andreas Gruenbacher
@ 2007-04-16 16:50           ` Randy Dunlap
  0 siblings, 0 replies; 187+ messages in thread
From: Randy Dunlap @ 2007-04-16 16:50 UTC (permalink / raw)
  To: Andreas Gruenbacher
  Cc: Christoph Hellwig, jjohansen, linux-kernel,
	linux-security-module, linux-fsdevel, chrisw, Tony Jones

Andreas Gruenbacher wrote:
> On Monday 16 April 2007 18:42, Randy Dunlap wrote:
>> Please don't use the kernel-doc begin-marker "/**" when the comment block
>> isn't in kernel-doc format.
> 
> Sigh, kernel-doc should improve things, not get in the way ...

Well, I see it as sort of a language that is embedded in C source code.

But what are you suggesting?

-- 
~Randy
*** Remember to use Documentation/SubmitChecklist when testing your code ***

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

* Re: [AppArmor 00/41] AppArmor security module overview
  2007-04-16  7:46     ` Pavel Machek
@ 2007-04-16 18:24       ` David Wagner
  0 siblings, 0 replies; 187+ messages in thread
From: David Wagner @ 2007-04-16 18:24 UTC (permalink / raw)
  To: linux-kernel

Pavel Machek  wrote:
> David Wagner wrote:
>> There was no way to follow fork securely.
>
>Actually there is now. I did something similar called subterfugue and
>we solved this one.

Yes, I saw that.  I thought subterfugue was neat.  The way that
subterfugue was a clever hack -- albeit too clever by half, in my opinion.
Dynamically re-writing the program on the fly to insert a trap after
the fork() call, right?  When the tracer has to do that kind of thing,
I find it hard to get confidence that it will be secure.  It seems
all too easy to imagine ways that the tracee might be able to escape
the tracing and break security.  There are all sorts of corner cases
to think about.  What if the program is executing from shared memory?
What if there are multiple threads running concurrently?  What if the
program is executing from a region of memory where a DMA is scheduled to
asynchronously write to?  Any of those cases could create a race condition
(TOCTTOU) where the trap after the fork() gets removed before the program
reaches that point of execution.

ptrace() seems like a fine answer for a debugger, but I think it's not
such a great answer for a security tool where you have to be dead-certain
there is no way to escape the sandbox.  When I'm relying upon something
for security, the last thing you want is to have to go through hairy
kludgy kludgy contortions to make up for flaws in the interface.
Complexity is the enemy of security.

I still think that ptrace() is not the best way to implement this kind
of security tool, and I think it's entirely understandable that they did
not use ptrace.  I do not think it is a fair criticism of AppArmor to say
"AppArmor should have used ptrace()".

>>  Handling of signals is a mess: ptrace overloads the
>> signal mechanism to deliver its events, [...]
>
>We got this solved in linux, I believe.

Out of curiousity, how was this solved?  It looked pretty fundamental
to me.

Thanks for your comments...

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

* Re: [AppArmor 39/41] AppArmor: Profile loading and manipulation, pathname matching
  2007-04-16  6:27       ` Andi Kleen
@ 2007-04-16 20:56         ` John Johansen
  0 siblings, 0 replies; 187+ messages in thread
From: John Johansen @ 2007-04-16 20:56 UTC (permalink / raw)
  To: Andi Kleen
  Cc: Andreas Gruenbacher, jjohansen, linux-kernel,
	linux-security-module, linux-fsdevel, chrisw

[-- Attachment #1: Type: text/plain, Size: 736 bytes --]

On Mon, Apr 16, 2007 at 08:27:08AM +0200, Andi Kleen wrote:
> > It's nice to check for consistency though, so we're adding that. Profile 
> > loading is a trusted operation, at least so far, and so security wise we 
> > don't actually have to care --- if loading an invalid profile can bring down 
> > the system, then that's no worse than an arbitrary module that crashes the 
> > machine. Not sure if there will ever be user loadable profiles; at least at 
> > that point we had to care.
> 
> A security system that allows to crash the kernel is a little weird 
> though. It would be better to check. Not that a recursion check
> is particularly expensive.
> 
Indeed.  It will be fixed in the next rev.

thanks
john


[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

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

* Re: [AppArmor 38/41] AppArmor: Module and LSM hooks
  2007-04-12 10:21   ` Alan Cox
@ 2007-04-16 21:37     ` John Johansen
  0 siblings, 0 replies; 187+ messages in thread
From: John Johansen @ 2007-04-16 21:37 UTC (permalink / raw)
  To: Alan Cox
  Cc: jjohansen, linux-kernel, linux-security-module, linux-fsdevel,
	chrisw, Andreas Gruenbacher

[-- Attachment #1: Type: text/plain, Size: 1765 bytes --]

On Thu, Apr 12, 2007 at 11:21:01AM +0100, Alan Cox wrote:
> > +
> > +	/**
> > +	 * parent can ptrace child when
> > +	 * - parent is unconfined
> > +	 * - parent is in complain mode
> > +	 * - parent and child are confined by the same profile
> > +	 */
> 
> Your profiles are name based. That means the same profile in a different
> namespace does different things. It would be a very odd case where it
> mattered but surely the parent ptrace child rule should also require that
> the parent and child are in the same namespace when using apparmor name
> based security.
> 
you are right we should be requiring parent and child are in the same
namespace.  This has been fixed.

> > +static int apparmor_capget(struct task_struct *task,
> > +			    kernel_cap_t *effective,
> > +			    kernel_cap_t *inheritable,
> > +			    kernel_cap_t *permitted)
> > +{
> > +	return cap_capget(task, effective, inheritable, permitted);
> > +}
> 
> Pointless function should go away.
> 
yes we had a few of those thanks for pointing it out.

> > +static int apparmor_sysctl(struct ctl_table *table, int op)
> > +{
> > +	int error = 0;
> > +
> > +	if ((op & 002) && !capable(CAP_SYS_ADMIN))
> > +		error = aa_reject_syscall(current, GFP_KERNEL,
> > +					  "sysctl (write)");
> > +
> > +	return error;
> 
> The usual file permission security override is DAC not ADMIN. What is the
> logic of this choice.
> 
This was a very course grain check that was done to restrict access to
sysctl's that could be potentially used to elevated priledge.  The check
is inconsistent with AppArmor's model and we should be modelling
sysctl accesses as pathname access, and then we could be using standard
mediation.

thanks for the review
john


[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

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

* Re: [AppArmor 31/41] Fix __d_path() for lazy unmounts and make it unambiguous; exclude unreachable mount points from /proc/mounts
  2007-04-15 17:40     ` Andreas Gruenbacher
@ 2007-04-16 21:57       ` Alan Cox
  2007-04-17  1:35         ` Andreas Gruenbacher
  2007-04-17  6:30         ` [AppArmor 31/41] Fix __d_path() for lazy unmounts and make it unambiguous; exclude unreachable mount points from /proc/mounts Rob Meijer
  0 siblings, 2 replies; 187+ messages in thread
From: Alan Cox @ 2007-04-16 21:57 UTC (permalink / raw)
  To: Andreas Gruenbacher
  Cc: jjohansen, linux-kernel, linux-security-module, linux-fsdevel,
	chrisw, Andrew Morton

> > That is a fairly significant and sudden change to the existing
> > kernel/user interface.
> 
> Well, this is not meant for 2.6.21. I hope it is possible to change it in 
> early 2.6.22; otherwise if we can't fix mistakes from the past we are pretty 
> doomed.

I don't believe the existing behaviour _IS_ a mistake.

> > This is untrue. The process can get there (via fd passing with another
> > task)
> 
> Process can access file descriptors which are unreachable via path name just 
> fine indeed, but those fds still don't have a valid path in the context of 
> that process.

Which while problematic to your name based security is just fine to
everything else. 

> We are only talking about mount points unreachable by a particular process; 
> this does not mean that the mount point isn't reachable by other processes. 
> Human operators can choose the context from which they are looking 
> at /proc/mounts. If they are looking form the "real" root, the will see all 
> mounts that any process can reach (in that namespace).

Ok, providing the "real" root sees them all it isn't so bad, but to
assume you can filter based upon what the task can see is dodgy as an
assumption.

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

* Re: [AppArmor 39/41] AppArmor: Profile loading and manipulation, pathname matching
  2007-04-15 14:21     ` Andreas Gruenbacher
  2007-04-16  6:27       ` Andi Kleen
  2007-04-16  7:39       ` Pavel Machek
@ 2007-04-16 22:00       ` Alan Cox
  2007-04-16 22:11         ` John Johansen
  2 siblings, 1 reply; 187+ messages in thread
From: Alan Cox @ 2007-04-16 22:00 UTC (permalink / raw)
  To: Andreas Gruenbacher
  Cc: Andi Kleen, jjohansen, linux-kernel, linux-security-module,
	linux-fsdevel, chrisw

> don't actually have to care --- if loading an invalid profile can bring down 
> the system, then that's no worse than an arbitrary module that crashes the 
> machine. Not sure if there will ever be user loadable profiles; at least at 
> that point we had to care.

CAP_SYS_RAWIO is needed to do arbitary patching/loading in the capability
model so if you are using lesser capabilities it is a (minor) capability
rise but not a big problem, just ugly and wanting a fix

> > > +	/*
> > > +	 * Replacement needs to allocate a new aa_task_context for each
> > > +	 * task confined by old_profile.  To do this the profile locks
> > > +	 * are only held when the actual switch is done per task.  While
> > > +	 * looping to allocate a new aa_task_context the old_task list
> > > +	 * may get shorter if tasks exit/change their profile but will
> > > +	 * not get longer as new task will not use old_profile detecting
> > > +	 * that is stale.
> > > +	 */
> > > +	do {
> > > +		new_cxt = aa_alloc_task_context(GFP_KERNEL | __GFP_NOFAIL);
> > 
> > NOFAIL is usually a bad sign. It should be only used if there is no
> > alternative.
> 
> At this point there is no secure alternative to allocating a task context --- 
> except killing the task, maybe.

Can you count the number needed, preallocate them and then when you know
for sure either succeed or fail the operation as a whole ?

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

* Re: [AppArmor 39/41] AppArmor: Profile loading and manipulation, pathname matching
  2007-04-16 22:00       ` Alan Cox
@ 2007-04-16 22:11         ` John Johansen
  0 siblings, 0 replies; 187+ messages in thread
From: John Johansen @ 2007-04-16 22:11 UTC (permalink / raw)
  To: Alan Cox
  Cc: Andreas Gruenbacher, Andi Kleen, jjohansen, linux-kernel,
	linux-security-module, linux-fsdevel, chrisw

[-- Attachment #1: Type: text/plain, Size: 1954 bytes --]

On Mon, Apr 16, 2007 at 11:00:01PM +0100, Alan Cox wrote:
> > don't actually have to care --- if loading an invalid profile can bring down 
> > the system, then that's no worse than an arbitrary module that crashes the 
> > machine. Not sure if there will ever be user loadable profiles; at least at 
> > that point we had to care.
> 
> CAP_SYS_RAWIO is needed to do arbitary patching/loading in the capability
> model so if you are using lesser capabilities it is a (minor) capability
> rise but not a big problem, just ugly and wanting a fix
> 
> > > > +	/*
> > > > +	 * Replacement needs to allocate a new aa_task_context for each
> > > > +	 * task confined by old_profile.  To do this the profile locks
> > > > +	 * are only held when the actual switch is done per task.  While
> > > > +	 * looping to allocate a new aa_task_context the old_task list
> > > > +	 * may get shorter if tasks exit/change their profile but will
> > > > +	 * not get longer as new task will not use old_profile detecting
> > > > +	 * that is stale.
> > > > +	 */
> > > > +	do {
> > > > +		new_cxt = aa_alloc_task_context(GFP_KERNEL | __GFP_NOFAIL);
> > > 
> > > NOFAIL is usually a bad sign. It should be only used if there is no
> > > alternative.
> > 
> > At this point there is no secure alternative to allocating a task context --- 
> > except killing the task, maybe.
> 
> Can you count the number needed, preallocate them and then when you know
> for sure either succeed or fail the operation as a whole ?

No, to be accurate the count would have to be made with the profile lock
held, which would then need to be released so as not to use GFP_ATOMIC
for the allocations.

An iterative approach could be taken where we do something like
repeat:
  lock profile
     count
     if preallocated < count
        unlock profile
        if (! allocate count - preallocated)
           Fail
        goto repeat
  do replacement

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

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

* Re: [AppArmor 31/41] Fix __d_path() for lazy unmounts and make it unambiguous; exclude unreachable mount points from /proc/mounts
  2007-04-16 21:57       ` Alan Cox
@ 2007-04-17  1:35         ` Andreas Gruenbacher
  2007-04-17 17:21           ` Alan Cox
  2007-04-17  6:30         ` [AppArmor 31/41] Fix __d_path() for lazy unmounts and make it unambiguous; exclude unreachable mount points from /proc/mounts Rob Meijer
  1 sibling, 1 reply; 187+ messages in thread
From: Andreas Gruenbacher @ 2007-04-17  1:35 UTC (permalink / raw)
  To: Alan Cox
  Cc: jjohansen, linux-kernel, linux-security-module, linux-fsdevel,
	chrisw, Andrew Morton

On Monday 16 April 2007 23:57, Alan Cox wrote:
> I don't believe the existing behaviour _IS_ a mistake.

So what would be the arguments why this behavior makes sense, other than 
legacy?

For /proc/mounts, one could argue that the admin might want to see everything, 
but then that's not actually true even today because /proc/mounts doesn't 
show lazyily unmounted stuff or mounts from other namespaces, so that 
everything is quite relative.

Along that line of argumentation, I would at least expect unambiguous output, 
to be able to tell which mountpoints are actually meaningful to the 
requesting process. It's not only human operators looking at /proc/mounts; 
applications care as well.

But after thinking about this issue quite a while, I really can't see what 
that should be good for. The current /proc/mounts interface is obviously 
broken; the chroot example should have demonstrated that. There are also 
unnecessary special cases because of that, such as having to filter out the 
rootfs entry when trying to figure out what's really mounted on /, and having 
to guess what's there and what's not in a particular context. The more 
complex mount scenarios will get, the more obviously broken the 
current /proc/mounts interface will become.

The getcwd() case is even stronger as the "see everything" argument makes even 
less sense there. I really can't see why the kernel should return processes 
fake pathnames. The process is explicitly asking for the current pathname to 
the working directory, it doesn't want to know what the pathname was at some 
previous point in time.

> > Process can access file descriptors which are unreachable via path name
> > just fine indeed, but those fds still don't have a valid path in the
> > context of that process.
> 
> Which while problematic to your name based security is just fine to
> everything else.

Actually, no. We could live fine with leaving getcwd() and /proc/mounts as 
ambiguous / weird / broken as they are right now. All it would take would be 
to reambiguate the result of the unambiguous __d_path(), which is really 
easy. Everything that cares about real pathnames would use the unambiguous 
version while the legacy interfaces would use the ambiguous version. But that 
really wouldn't make sense.

> Ok, providing the "real" root sees them all it isn't so bad, but to
> assume you can filter based upon what the task can see is dodgy as an
> assumption.

Why?

Thanks,
Andreas

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

* Re: [AppArmor 31/41] Fix __d_path() for lazy unmounts and make it  unambiguous; exclude unreachable mount points from /proc/mounts
  2007-04-16 21:57       ` Alan Cox
  2007-04-17  1:35         ` Andreas Gruenbacher
@ 2007-04-17  6:30         ` Rob Meijer
  1 sibling, 0 replies; 187+ messages in thread
From: Rob Meijer @ 2007-04-17  6:30 UTC (permalink / raw)
  To: Alan Cox
  Cc: Andreas Gruenbacher, jjohansen, linux-kernel,
	linux-security-module, linux-fsdevel, chrisw, Andrew Morton

On Mon, April 16, 2007 23:57, Alan Cox wrote:
>> > That is a fairly significant and sudden change to the existing
>> > kernel/user interface.
>>
>> Well, this is not meant for 2.6.21. I hope it is possible to change it
>> in
>> early 2.6.22; otherwise if we can't fix mistakes from the past we are
>> pretty
>> doomed.
>
> I don't believe the existing behaviour _IS_ a mistake.
>
>> > This is untrue. The process can get there (via fd passing with another
>> > task)
>>
>> Process can access file descriptors which are unreachable via path name
>> just
>> fine indeed, but those fds still don't have a valid path in the context
>> of
>> that process.
>
> Which while problematic to your name based security is just fine to
> everything else.

The realisation that I feel needs to be made is that fd passing is a
legitimate transfer of authority, and attempting to block the usage of
this authority (or block the transfer of this authority) would be
extremely bad.

One thing however that does need some major attention is the amounth of
and the scope of the authority that is being transfered with directory
file handles.




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

* Re: [nameidata 1/2] Don't pass NULL nameidata to vfs_create
  2007-04-16 16:45           ` Christoph Hellwig
@ 2007-04-17 12:09             ` Andreas Gruenbacher
  0 siblings, 0 replies; 187+ messages in thread
From: Andreas Gruenbacher @ 2007-04-17 12:09 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: jjohansen, linux-kernel, linux-security-module, linux-fsdevel,
	chrisw, Tony Jones

On Monday 16 April 2007 18:45, Christoph Hellwig wrote:
> You should provide intent information, yes - which your patch didn't :)

Well, the information implicitly provided is "no intent": In do_create() in
ipc/mqueue.c intents would be pretty pointless because the mqueue filesystem
is local. In fs/nfsd/vfs.c, intents would make slightly more sense assuming
that the underlying filesystem eported via nfsd is remote. That's an
optimization, and not even a very important one.

> (Which btw, I expect to cause quite a few problems for apparmor or other
> lsms, but I guess so far no one has tried them on NFSv4)

Pathname wise, NFSv4 should look like any other filesystem on the client side. 
On the Server side, the concept of pathnames doesn't really fly for nfs: if a 
directory contains more than one link to the same file, there is no way to 
tell those aliases from each other from the file descriptor. In addition, 
computing even the somewhat ambiguous pathnames that can be computed would
require subtree checking. But trying to confine nfsd is pretty pointless 
anyway: the deamon is privileged and can do whatever it wants. It makes more
sense to export the right directories with the right permissions in the first
place.

Thanks,
Andreas

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

* Re: [AppArmor 31/41] Fix __d_path() for lazy unmounts and make it unambiguous; exclude unreachable mount points from /proc/mounts
  2007-04-17  1:35         ` Andreas Gruenbacher
@ 2007-04-17 17:21           ` Alan Cox
  2007-04-19 23:23             ` [d_path 0/7] Fixes to d_path: Respin Andreas Gruenbacher
  0 siblings, 1 reply; 187+ messages in thread
From: Alan Cox @ 2007-04-17 17:21 UTC (permalink / raw)
  To: Andreas Gruenbacher
  Cc: jjohansen, linux-kernel, linux-security-module, linux-fsdevel,
	chrisw, Andrew Morton

> For /proc/mounts, one could argue that the admin might want to see everything, 
> but then that's not actually true even today because /proc/mounts doesn't 
> show lazyily unmounted stuff or mounts from other namespaces, so that 
> everything is quite relative.

The current state is not good either

> The getcwd() case is even stronger as the "see everything" argument makes even 
> less sense there. I really can't see why the kernel should return processes 
> fake pathnames. The process is explicitly asking for the current pathname to 
> the working directory, it doesn't want to know what the pathname was at some 
> previous point in time.

Can you prove no existing application on the planet relies on the
existing behaviour ? Actually more limited but sane as a test would be
"Can you prove that the glibc behaviour visible to applications does not
change"

> Actually, no. We could live fine with leaving getcwd() and /proc/mounts as 
> ambiguous / weird / broken as they are right now. All it would take would be 
> to reambiguate the result of the unambiguous __d_path(), which is really 
> easy. Everything that cares about real pathnames would use the unambiguous 
> version while the legacy interfaces would use the ambiguous version. But that 
> really wouldn't make sense.

I disagree - firstly because of not breaking stuff, and secondly because
it separates two discussions - merging AppArmor being one of them , and
the correct behaviour for getcwd & /proc/mounts being the other.

> > Ok, providing the "real" root sees them all it isn't so bad, but to
> > assume you can filter based upon what the task can see is dodgy as an
> > assumption.
> 
> Why?

Because the viewing apparatus on the other side of the monitor is not
operating in current directories/contexts.

Alan

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

* [d_path 0/7] Fixes to d_path: Respin
  2007-04-17 17:21           ` Alan Cox
@ 2007-04-19 23:23             ` Andreas Gruenbacher
  2007-04-19 23:23               ` [d_path 1/7] Fix __d_path() for lazy unmounts and make it unambiguous Andreas Gruenbacher
                                 ` (7 more replies)
  0 siblings, 8 replies; 187+ messages in thread
From: Andreas Gruenbacher @ 2007-04-19 23:23 UTC (permalink / raw)
  To: Alan Cox
  Cc: jjohansen, linux-kernel, linux-security-module, linux-fsdevel,
	chrisw, Andrew Morton

On Tuesday 17 April 2007 19:21, Alan Cox wrote:
> Can you prove no existing application on the planet relies on the
> existing behaviour ? Actually more limited but sane as a test would be
> "Can you prove that the glibc behaviour visible to applications does not
> change"

As far as I can see, glibc internally looks at /proc/mounts (or else mtab) to
find out where tmpfs is mounted for opening files there, and to look up
filesystem information for statfs(), while accessing that path, too. Fstatfs()
also looks into the same files, but it only matches by filesystem type, so this
is only a very unreliable heuristic, anyway.

So judging from that, glibc users should be fine.

> I disagree - firstly because of not breaking stuff, and secondly because
> it separates two discussions - merging AppArmor being one of them , and
> the correct behaviour for getcwd & /proc/mounts being the other.

I agree with the separation of discussion argument. Here are patches that
change getcwd() and /proc/mounts independent of the changes that AppArmor
depends on.

Thanks for your feedback!

Andreas


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

* [d_path 1/7] Fix __d_path() for lazy unmounts and make it unambiguous
  2007-04-19 23:23             ` [d_path 0/7] Fixes to d_path: Respin Andreas Gruenbacher
@ 2007-04-19 23:23               ` Andreas Gruenbacher
  2007-04-20  9:32                 ` Alan Cox
  2007-04-19 23:23               ` [d_path 2/7] Make d_path() consistent across mount operations Andreas Gruenbacher
                                 ` (6 subsequent siblings)
  7 siblings, 1 reply; 187+ messages in thread
From: Andreas Gruenbacher @ 2007-04-19 23:23 UTC (permalink / raw)
  To: Alan Cox
  Cc: jjohansen, linux-kernel, linux-security-module, linux-fsdevel,
	chrisw, Andrew Morton

[-- Attachment #1: unambiguous-__d_path.diff --]
[-- Type: text/plain, Size: 8085 bytes --]

First, when __d_path() hits a lazily unmounted mount point, it tries to prepend
the name of the lazily unmounted dentry to the path name.  It gets this wrong,
and also overwrites the slash that separates the name from the following
pathname component. This patch fixes that; if a process was in directory
/foo/bar and /foo got lazily unmounted, the old result was ``foobar'' (note the
missing slash), while the new result with this patch is ``foo/bar''.

Second, it isn't always possible to tell from the __d_path() result whether the
specified root and rootmnt (i.e., the chroot) was reached.  We need an
unambiguous result for AppArmor at least though, so we make sure that paths
will only start with a slash if the path leads all the way up to the root.

We also add a @fail_deleted argument, which allows to get rid of some of the
mess in sys_getcwd().

This patch leaves getcwd() and d_path() as they were before for everything
except for bind-mounted directories; for them, it reports ``/foo/bar'' instead
of ``foobar'' in the example described above.  Subsequent patches propose to
make getcwd() fail instead of reporting unreachable paths like this one and
hide unreachable mount points from /proc/mounts.

Signed-off-by: Andreas Gruenbacher <agruen@suse.de>

---
 fs/dcache.c |  169 ++++++++++++++++++++++++++++++++++--------------------------
 1 file changed, 98 insertions(+), 71 deletions(-)

--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1732,52 +1732,51 @@ shouldnt_be_hashed:
 }
 
 /**
- * d_path - return the path of a dentry
+ * __d_path - return the path of a dentry
  * @dentry: dentry to report
  * @vfsmnt: vfsmnt to which the dentry belongs
  * @root: root dentry
  * @rootmnt: vfsmnt to which the root dentry belongs
  * @buffer: buffer to return value in
  * @buflen: buffer length
+ * @fail_deleted: what to return for deleted files
  *
- * Convert a dentry into an ASCII path name. If the entry has been deleted
+ * Convert a dentry into an ASCII path name. If the entry has been deleted,
+ * then if @fail_deleted is true, ERR_PTR(-ENOENT) is returned. Otherwise,
  * the string " (deleted)" is appended. Note that this is ambiguous.
  *
- * Returns the buffer or an error code if the path was too long.
+ * If @dentry is not connected to @root, the path returned will be relative
+ * (i.e., it will not start with a slash).
  *
- * "buflen" should be positive. Caller holds the dcache_lock.
+ * Returns the buffer or an error code.
  */
-static char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt,
-			struct dentry *root, struct vfsmount *rootmnt,
-			char *buffer, int buflen)
-{
-	char * end = buffer+buflen;
-	char * retval;
-	int namelen;
+static char *__d_path(struct dentry *dentry, struct vfsmount *vfsmnt,
+		      struct dentry *root, struct vfsmount *rootmnt,
+		      char *buffer, int buflen, int fail_deleted)
+{
+	int namelen, is_slash;
+
+	if (buflen < 2)
+		return ERR_PTR(-ENAMETOOLONG);
+	buffer += --buflen;
+	*buffer = '\0';
 
-	*--end = '\0';
-	buflen--;
+	spin_lock(&dcache_lock);
 	if (!IS_ROOT(dentry) && d_unhashed(dentry)) {
-		buflen -= 10;
-		end -= 10;
-		if (buflen < 0)
+		if (fail_deleted) {
+			buffer = ERR_PTR(-ENOENT);
+			goto out;
+		}
+		if (buflen < 10)
 			goto Elong;
-		memcpy(end, " (deleted)", 10);
+		buflen -= 10;
+		buffer -= 10;
+		memcpy(buffer, " (deleted)", 10);
 	}
-
-	if (buflen < 1)
-		goto Elong;
-	/* Get '/' right */
-	retval = end-1;
-	*retval = '/';
-
-	for (;;) {
+	while (dentry != root || vfsmnt != rootmnt) {
 		struct dentry * parent;
 
-		if (dentry == root && vfsmnt == rootmnt)
-			break;
 		if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
-			/* Global root? */
 			spin_lock(&vfsmount_lock);
 			if (vfsmnt->mnt_parent == vfsmnt) {
 				spin_unlock(&vfsmount_lock);
@@ -1791,33 +1790,72 @@ static char * __d_path( struct dentry *d
 		parent = dentry->d_parent;
 		prefetch(parent);
 		namelen = dentry->d_name.len;
-		buflen -= namelen + 1;
-		if (buflen < 0)
+		if (buflen < namelen + 1)
 			goto Elong;
-		end -= namelen;
-		memcpy(end, dentry->d_name.name, namelen);
-		*--end = '/';
-		retval = end;
+		buflen -= namelen + 1;
+		buffer -= namelen;
+		memcpy(buffer, dentry->d_name.name, namelen);
+		*--buffer = '/';
 		dentry = parent;
 	}
+	/* Get '/' right. */
+	if (*buffer != '/')
+		*--buffer = '/';
 
-	return retval;
+out:
+	spin_unlock(&dcache_lock);
+	return buffer;
 
 global_root:
+	/*
+	 * We went past the (vfsmount, dentry) we were looking for and have
+	 * either hit a root dentry, a lazily unmounted dentry, an
+	 * unconnected dentry, or the file is on a pseudo filesystem.
+	 */
 	namelen = dentry->d_name.len;
-	buflen -= namelen;
-	if (buflen < 0)
+	is_slash = (namelen == 1 && *dentry->d_name.name == '/');
+	if (is_slash || (dentry->d_sb->s_flags & MS_NOUSER)) {
+		/*
+		 * Make sure we won't return a pathname starting with '/'.
+		 *
+		 * Historically, we also glue together the root dentry and
+		 * remaining name for pseudo filesystems like pipefs, which
+		 * have the MS_NOUSER flag set. This results in pathnames
+		 * like "pipe:[439336]".
+		 */
+		if (*buffer == '/') {
+			buffer++;
+			buflen++;
+		}
+		if (is_slash)
+			goto out;
+	}
+	if (buflen < namelen)
 		goto Elong;
-	retval -= namelen-1;	/* hit the slash */
-	memcpy(retval, dentry->d_name.name, namelen);
-	return retval;
+	buffer -= namelen;
+	memcpy(buffer, dentry->d_name.name, namelen);
+	goto out;
+
 Elong:
-	return ERR_PTR(-ENAMETOOLONG);
+	buffer = ERR_PTR(-ENAMETOOLONG);
+	goto out;
+}
+
+static char *__connect_d_path(char *path, char *buffer)
+{
+	if (!IS_ERR(path) && *path != '/') {
+		/* Pretend that disconnected paths are hanging off the root. */
+		if (path == buffer)
+			path = ERR_PTR(-ENAMETOOLONG);
+		else
+			*--path = '/';
+	}
+	return path;
 }
 
 /* write full pathname into buffer and return start of pathname */
-char * d_path(struct dentry *dentry, struct vfsmount *vfsmnt,
-				char *buf, int buflen)
+char *d_path(struct dentry *dentry, struct vfsmount *vfsmnt, char *buf,
+	     int buflen)
 {
 	char *res;
 	struct vfsmount *rootmnt;
@@ -1827,9 +1865,8 @@ char * d_path(struct dentry *dentry, str
 	rootmnt = mntget(current->fs->rootmnt);
 	root = dget(current->fs->root);
 	read_unlock(&current->fs->lock);
-	spin_lock(&dcache_lock);
-	res = __d_path(dentry, vfsmnt, root, rootmnt, buf, buflen);
-	spin_unlock(&dcache_lock);
+	res = __d_path(dentry, vfsmnt, root, rootmnt, buf, buflen, 0);
+	res = __connect_d_path(res, buf);
 	dput(root);
 	mntput(rootmnt);
 	return res;
@@ -1855,10 +1892,10 @@ char * d_path(struct dentry *dentry, str
  */
 asmlinkage long sys_getcwd(char __user *buf, unsigned long size)
 {
-	int error;
+	int error, len;
 	struct vfsmount *pwdmnt, *rootmnt;
 	struct dentry *pwd, *root;
-	char *page = (char *) __get_free_page(GFP_USER);
+	char *page = (char *) __get_free_page(GFP_USER), *cwd;
 
 	if (!page)
 		return -ENOMEM;
@@ -1870,29 +1907,19 @@ asmlinkage long sys_getcwd(char __user *
 	root = dget(current->fs->root);
 	read_unlock(&current->fs->lock);
 
-	error = -ENOENT;
-	/* Has the current directory has been unlinked? */
-	spin_lock(&dcache_lock);
-	if (pwd->d_parent == pwd || !d_unhashed(pwd)) {
-		unsigned long len;
-		char * cwd;
-
-		cwd = __d_path(pwd, pwdmnt, root, rootmnt, page, PAGE_SIZE);
-		spin_unlock(&dcache_lock);
-
-		error = PTR_ERR(cwd);
-		if (IS_ERR(cwd))
-			goto out;
-
-		error = -ERANGE;
-		len = PAGE_SIZE + page - cwd;
-		if (len <= size) {
-			error = len;
-			if (copy_to_user(buf, cwd, len))
-				error = -EFAULT;
-		}
-	} else
-		spin_unlock(&dcache_lock);
+	cwd = __d_path(pwd, pwdmnt, root, rootmnt, page, PAGE_SIZE, 1);
+	cwd = __connect_d_path(cwd, page);
+	error = PTR_ERR(cwd);
+	if (IS_ERR(cwd))
+		goto out;
+
+	error = -ERANGE;
+	len = PAGE_SIZE + page - cwd;
+	if (len <= size) {
+		error = len;
+		if (copy_to_user(buf, cwd, len))
+			error = -EFAULT;
+	}
 
 out:
 	dput(pwd);

-- 
Andreas Gruenbacher <agruen@suse.de>
SUSE Labs, SUSE LINUX Products GmbH
GF: Markus Rex, HRB 16746 (AG Nuernberg)

GPG: AF77 FAD1 1819 D442 400F  4BC8 409A 6903 4FDD EE02


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

* [d_path 2/7] Make d_path() consistent across mount operations
  2007-04-19 23:23             ` [d_path 0/7] Fixes to d_path: Respin Andreas Gruenbacher
  2007-04-19 23:23               ` [d_path 1/7] Fix __d_path() for lazy unmounts and make it unambiguous Andreas Gruenbacher
@ 2007-04-19 23:23               ` Andreas Gruenbacher
  2007-04-19 23:23               ` [d_path 3/7] Add d_namespace_path() to compute namespace relative pathnames Andreas Gruenbacher
                                 ` (5 subsequent siblings)
  7 siblings, 0 replies; 187+ messages in thread
From: Andreas Gruenbacher @ 2007-04-19 23:23 UTC (permalink / raw)
  To: Alan Cox
  Cc: jjohansen, linux-kernel, linux-security-module, linux-fsdevel,
	chrisw, Andrew Morton

[-- Attachment #1: mount-consistent-__d_path.diff --]
[-- Type: text/plain, Size: 1971 bytes --]

The path that __d_path() computes can become slightly inconsistent when it
races with mount operations: it grabs the vfsmount_lock when traversing mount
points, but immediately drops it again, only to re-grab it when it reaches the
next mount point.  The result is that the filename computed is not always
consisent, and the file may never have had that name. (This is unlikely, but
still possible.)

Fix this by grabbing the vfsmount_lock when the first mount point is reached,
and holding onto it until the d_cache lookup is completed.

Signed-off-by: Andreas Gruenbacher <agruen@suse.de>

---
 fs/dcache.c |   14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1754,7 +1754,7 @@ static char *__d_path(struct dentry *den
 		      struct dentry *root, struct vfsmount *rootmnt,
 		      char *buffer, int buflen, int fail_deleted)
 {
-	int namelen, is_slash;
+	int namelen, is_slash, vfsmount_locked = 0;
 
 	if (buflen < 2)
 		return ERR_PTR(-ENAMETOOLONG);
@@ -1777,14 +1777,14 @@ static char *__d_path(struct dentry *den
 		struct dentry * parent;
 
 		if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
-			spin_lock(&vfsmount_lock);
-			if (vfsmnt->mnt_parent == vfsmnt) {
-				spin_unlock(&vfsmount_lock);
-				goto global_root;
+			if (!vfsmount_locked) {
+				spin_lock(&vfsmount_lock);
+				vfsmount_locked = 1;
 			}
+			if (vfsmnt->mnt_parent == vfsmnt)
+				goto global_root;
 			dentry = vfsmnt->mnt_mountpoint;
 			vfsmnt = vfsmnt->mnt_parent;
-			spin_unlock(&vfsmount_lock);
 			continue;
 		}
 		parent = dentry->d_parent;
@@ -1803,6 +1803,8 @@ static char *__d_path(struct dentry *den
 		*--buffer = '/';
 
 out:
+	if (vfsmount_locked)
+		spin_unlock(&vfsmount_lock);
 	spin_unlock(&dcache_lock);
 	return buffer;
 

-- 
Andreas Gruenbacher <agruen@suse.de>
SUSE Labs, SUSE LINUX Products GmbH
GF: Markus Rex, HRB 16746 (AG Nuernberg)

GPG: AF77 FAD1 1819 D442 400F  4BC8 409A 6903 4FDD EE02


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

* [d_path 3/7] Add d_namespace_path() to compute namespace relative pathnames
  2007-04-19 23:23             ` [d_path 0/7] Fixes to d_path: Respin Andreas Gruenbacher
  2007-04-19 23:23               ` [d_path 1/7] Fix __d_path() for lazy unmounts and make it unambiguous Andreas Gruenbacher
  2007-04-19 23:23               ` [d_path 2/7] Make d_path() consistent across mount operations Andreas Gruenbacher
@ 2007-04-19 23:23               ` Andreas Gruenbacher
  2007-04-21 12:57                 ` Tetsuo Handa
  2007-04-19 23:23               ` [d_path 4/7] Make getcwd() only return valid paths Andreas Gruenbacher
                                 ` (4 subsequent siblings)
  7 siblings, 1 reply; 187+ messages in thread
From: Andreas Gruenbacher @ 2007-04-19 23:23 UTC (permalink / raw)
  To: Alan Cox
  Cc: jjohansen, linux-kernel, linux-security-module, linux-fsdevel,
	chrisw, Andrew Morton

[-- Attachment #1: d_namespace_path.diff --]
[-- Type: text/plain, Size: 2933 bytes --]

In AppArmor, we are interested in pathnames relative to the namespace root.
This is the same as d_path() except for the root where the search ends. Add
a function for computing the namespace-relative path.

Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Reviewed-by: John Johansen <jjohansen@suse.de>

---
 fs/dcache.c            |    6 +++---
 fs/namespace.c         |   27 +++++++++++++++++++++++++++
 include/linux/dcache.h |    2 ++
 include/linux/mount.h  |    2 ++
 4 files changed, 34 insertions(+), 3 deletions(-)

--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1750,9 +1750,9 @@ shouldnt_be_hashed:
  *
  * Returns the buffer or an error code.
  */
-static char *__d_path(struct dentry *dentry, struct vfsmount *vfsmnt,
-		      struct dentry *root, struct vfsmount *rootmnt,
-		      char *buffer, int buflen, int fail_deleted)
+char *__d_path(struct dentry *dentry, struct vfsmount *vfsmnt,
+	       struct dentry *root, struct vfsmount *rootmnt,
+	       char *buffer, int buflen, int fail_deleted)
 {
 	int namelen, is_slash, vfsmount_locked = 0;
 
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -1877,3 +1877,30 @@ void __put_mnt_ns(struct mnt_namespace *
 	release_mounts(&umount_list);
 	kfree(ns);
 }
+
+char *d_namespace_path(struct dentry *dentry, struct vfsmount *vfsmnt,
+		       char *buf, int buflen)
+{
+	struct vfsmount *rootmnt, *nsrootmnt = NULL;
+	struct dentry *root = NULL;
+	char *res;
+
+	read_lock(&current->fs->lock);
+	rootmnt = mntget(current->fs->rootmnt);
+	read_unlock(&current->fs->lock);
+	spin_lock(&vfsmount_lock);
+	if (rootmnt->mnt_ns)
+		nsrootmnt = mntget(rootmnt->mnt_ns->root);
+	spin_unlock(&vfsmount_lock);
+	mntput(rootmnt);
+	if (nsrootmnt)
+		root = dget(nsrootmnt->mnt_root);
+	res = __d_path(dentry, vfsmnt, root, nsrootmnt, buf, buflen, 1);
+	dput(root);
+	mntput(nsrootmnt);
+	/* Prevent empty path for lazily unmounted filesystems. */
+	if (!IS_ERR(res) && *res == '\0')
+		*--res = '.';
+	return res;
+}
+EXPORT_SYMBOL(d_namespace_path);
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -293,6 +293,8 @@ extern struct dentry * d_hash_and_lookup
 /* validate "insecure" dentry pointer */
 extern int d_validate(struct dentry *, struct dentry *);
 
+extern char *__d_path(struct dentry *, struct vfsmount *, struct dentry *,
+		      struct vfsmount *, char *, int, int);
 extern char * d_path(struct dentry *, struct vfsmount *, char *, int);
   
 /* Allocation counts.. */
--- a/include/linux/mount.h
+++ b/include/linux/mount.h
@@ -103,5 +103,7 @@ extern void shrink_submounts(struct vfsm
 extern spinlock_t vfsmount_lock;
 extern dev_t name_to_dev_t(char *name);
 
+extern char *d_namespace_path(struct dentry *, struct vfsmount *, char *, int);
+
 #endif
 #endif /* _LINUX_MOUNT_H */

-- 
Andreas Gruenbacher <agruen@suse.de>
SUSE Labs, SUSE LINUX Products GmbH
GF: Markus Rex, HRB 16746 (AG Nuernberg)

GPG: AF77 FAD1 1819 D442 400F  4BC8 409A 6903 4FDD EE02


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

* [d_path 4/7] Make getcwd() only return valid paths
  2007-04-19 23:23             ` [d_path 0/7] Fixes to d_path: Respin Andreas Gruenbacher
                                 ` (2 preceding siblings ...)
  2007-04-19 23:23               ` [d_path 3/7] Add d_namespace_path() to compute namespace relative pathnames Andreas Gruenbacher
@ 2007-04-19 23:23               ` Andreas Gruenbacher
  2007-04-19 23:23               ` [d_path 5/7] Remove duplicate proc code Andreas Gruenbacher
                                 ` (3 subsequent siblings)
  7 siblings, 0 replies; 187+ messages in thread
From: Andreas Gruenbacher @ 2007-04-19 23:23 UTC (permalink / raw)
  To: Alan Cox
  Cc: jjohansen, linux-kernel, linux-security-module, linux-fsdevel,
	chrisw, Andrew Morton

[-- Attachment #1: fix-getcwd.diff --]
[-- Type: text/plain, Size: 961 bytes --]

Make getcwd() fail with -ENOENT if the current working directory is
disconnected: the process is not asking for some previous name of that
directory but for the current name; returning a path meaningless in the
context of that process makes no sense.

Signed-off-by: Andreas Gruenbacher <agruen@suse.de>

---
 fs/dcache.c |    4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1910,10 +1910,12 @@ asmlinkage long sys_getcwd(char __user *
 	read_unlock(&current->fs->lock);
 
 	cwd = __d_path(pwd, pwdmnt, root, rootmnt, page, PAGE_SIZE, 1);
-	cwd = __connect_d_path(cwd, page);
 	error = PTR_ERR(cwd);
 	if (IS_ERR(cwd))
 		goto out;
+	error = -ENOENT;
+	if (*cwd != '/')
+		goto out;
 
 	error = -ERANGE;
 	len = PAGE_SIZE + page - cwd;

-- 
Andreas Gruenbacher <agruen@suse.de>
SUSE Labs, SUSE LINUX Products GmbH
GF: Markus Rex, HRB 16746 (AG Nuernberg)

GPG: AF77 FAD1 1819 D442 400F  4BC8 409A 6903 4FDD EE02


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

* [d_path 5/7] Remove duplicate proc code
  2007-04-19 23:23             ` [d_path 0/7] Fixes to d_path: Respin Andreas Gruenbacher
                                 ` (3 preceding siblings ...)
  2007-04-19 23:23               ` [d_path 4/7] Make getcwd() only return valid paths Andreas Gruenbacher
@ 2007-04-19 23:23               ` Andreas Gruenbacher
  2007-04-19 23:23               ` [d_path 6/7] Filter out disconnected paths from /proc/mounts Andreas Gruenbacher
                                 ` (2 subsequent siblings)
  7 siblings, 0 replies; 187+ messages in thread
From: Andreas Gruenbacher @ 2007-04-19 23:23 UTC (permalink / raw)
  To: Alan Cox
  Cc: jjohansen, linux-kernel, linux-security-module, linux-fsdevel,
	chrisw, Andrew Morton

[-- Attachment #1: proc-mounts-cleanup.diff --]
[-- Type: text/plain, Size: 2742 bytes --]

Remove some duplicate code in generating the contents of /proc/mounts and
/proc/$pid/mountstats.

Signed-off-by: Andreas Gruenbacher <agruen@suse.de>

---
 fs/proc/base.c |   45 +++++++++++++++------------------------------
 1 file changed, 15 insertions(+), 30 deletions(-)

--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -359,7 +359,8 @@ struct proc_mounts {
 	int event;
 };
 
-static int mounts_open(struct inode *inode, struct file *file)
+static int __mounts_open(struct inode *inode, struct file *file,
+			 struct seq_operations *seq_ops)
 {
 	struct task_struct *task = get_proc_task(inode);
 	struct mnt_namespace *ns = NULL;
@@ -382,7 +383,7 @@ static int mounts_open(struct inode *ino
 		p = kmalloc(sizeof(struct proc_mounts), GFP_KERNEL);
 		if (p) {
 			file->private_data = &p->m;
-			ret = seq_open(file, &mounts_op);
+			ret = seq_open(file, seq_ops);
 			if (!ret) {
 				p->m.private = ns;
 				p->event = ns->event;
@@ -395,17 +396,25 @@ static int mounts_open(struct inode *ino
 	return ret;
 }
 
+static int mounts_open(struct inode *inode, struct file *file)
+{
+	return __mounts_open(inode, file, &mounts_op);
+}
+
 static int mounts_release(struct inode *inode, struct file *file)
 {
-	struct seq_file *m = file->private_data;
-	struct mnt_namespace *ns = m->private;
+	struct proc_mounts *p =
+		container_of(file->private_data, struct proc_mounts, m);
+	struct mnt_namespace *ns = p->m.private;
+
 	put_mnt_ns(ns);
 	return seq_release(inode, file);
 }
 
 static unsigned mounts_poll(struct file *file, poll_table *wait)
 {
-	struct proc_mounts *p = file->private_data;
+	struct proc_mounts *p =
+		container_of(file->private_data, struct proc_mounts, m);
 	struct mnt_namespace *ns = p->m.private;
 	unsigned res = 0;
 
@@ -432,31 +441,7 @@ static const struct file_operations proc
 extern struct seq_operations mountstats_op;
 static int mountstats_open(struct inode *inode, struct file *file)
 {
-	int ret = seq_open(file, &mountstats_op);
-
-	if (!ret) {
-		struct seq_file *m = file->private_data;
-		struct mnt_namespace *mnt_ns = NULL;
-		struct task_struct *task = get_proc_task(inode);
-
-		if (task) {
-			task_lock(task);
-			if (task->nsproxy)
-				mnt_ns = task->nsproxy->mnt_ns;
-			if (mnt_ns)
-				get_mnt_ns(mnt_ns);
-			task_unlock(task);
-			put_task_struct(task);
-		}
-
-		if (mnt_ns)
-			m->private = mnt_ns;
-		else {
-			seq_release(inode, file);
-			ret = -EINVAL;
-		}
-	}
-	return ret;
+	return __mounts_open(inode, file, &mountstats_op);
 }
 
 static const struct file_operations proc_mountstats_operations = {

-- 
Andreas Gruenbacher <agruen@suse.de>
SUSE Labs, SUSE LINUX Products GmbH
GF: Markus Rex, HRB 16746 (AG Nuernberg)

GPG: AF77 FAD1 1819 D442 400F  4BC8 409A 6903 4FDD EE02


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

* [d_path 6/7] Filter out disconnected paths from /proc/mounts
  2007-04-19 23:23             ` [d_path 0/7] Fixes to d_path: Respin Andreas Gruenbacher
                                 ` (4 preceding siblings ...)
  2007-04-19 23:23               ` [d_path 5/7] Remove duplicate proc code Andreas Gruenbacher
@ 2007-04-19 23:23               ` Andreas Gruenbacher
  2007-04-20  9:34                 ` Alan Cox
  2007-04-19 23:23               ` [d_path 7/7] Distinguish between connected and disconnected paths in d_path() Andreas Gruenbacher
  2007-04-20  9:30               ` [d_path 0/7] Fixes to d_path: Respin Alan Cox
  7 siblings, 1 reply; 187+ messages in thread
From: Andreas Gruenbacher @ 2007-04-19 23:23 UTC (permalink / raw)
  To: Alan Cox
  Cc: jjohansen, linux-kernel, linux-security-module, linux-fsdevel,
	chrisw, Andrew Morton

[-- Attachment #1: proc-mounts-check-d_path-result.diff --]
[-- Type: text/plain, Size: 3947 bytes --]

Use d_path() instead of seq_path when generating /proc/mounts and
/proc/$id/mountstats, reuse the same buffer for all mounts, and filter out
disconnected paths.

This path has no net effect in itself because d_path() so far doesn't
distinguish sconnected and disconnected paths yet. The next patch fixes that
though; without this patch, the next patch would break /proc/mounts and
/proc/$id/mountstats.

There is some disagreement what /proc/mounts should include. Currently it
reports all mounts from the current namespace and doesn't include lazy
unmounts. This leads to ambiguities with the rootfs (which is an internal mount
irrelevant to user-space except in the initrd), and in chroots.

With this and the next patch, /proc/mounts only reports the mounts reachable
for the current process, which makes a lot more sense IMO.  If the current
process is rooted in the namespace root (which it usually is), it will see all
mounts except for the rootfs.

Signed-off-by: Andreas Gruenbacher <agruen@suse.de>

---
 fs/namespace.c |   23 +++++++++++++++++++++--
 fs/proc/base.c |   10 +++++++++-
 2 files changed, 30 insertions(+), 3 deletions(-)

--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -348,8 +348,16 @@ static inline void mangle(struct seq_fil
 	seq_escape(m, s, " \t\n\\");
 }
 
+/* Keep in sync with fs/proc/base.c! */
+struct proc_mounts {
+	struct seq_file m;
+	void *page;
+	int event;
+};
+
 static int show_vfsmnt(struct seq_file *m, void *v)
 {
+	void *page = container_of(m, struct proc_mounts, m)->page;
 	struct vfsmount *mnt = v;
 	int err = 0;
 	static struct proc_fs_info {
@@ -371,10 +379,15 @@ static int show_vfsmnt(struct seq_file *
 		{ 0, NULL }
 	};
 	struct proc_fs_info *fs_infop;
+	char *path;
+
+	path = d_path(mnt->mnt_root, mnt, page, PAGE_SIZE);
+	if (IS_ERR(path) || *path != '/')
+		return err;
 
 	mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none");
 	seq_putc(m, ' ');
-	seq_path(m, mnt, mnt->mnt_root, " \t\n\\");
+	mangle(m, path);
 	seq_putc(m, ' ');
 	mangle(m, mnt->mnt_sb->s_type->name);
 	seq_puts(m, mnt->mnt_sb->s_flags & MS_RDONLY ? " ro" : " rw");
@@ -401,8 +414,14 @@ struct seq_operations mounts_op = {
 
 static int show_vfsstat(struct seq_file *m, void *v)
 {
+	void *page = container_of(m, struct proc_mounts, m)->page;
 	struct vfsmount *mnt = v;
 	int err = 0;
+	char *path;
+
+	path = d_path(mnt->mnt_root, mnt, page, PAGE_SIZE);
+	if (IS_ERR(path) || *path != '/')
+		return err; /* error or path unreachable from chroot */
 
 	/* device */
 	if (mnt->mnt_devname) {
@@ -413,7 +432,7 @@ static int show_vfsstat(struct seq_file 
 
 	/* mount point */
 	seq_puts(m, " mounted on ");
-	seq_path(m, mnt, mnt->mnt_root, " \t\n\\");
+	mangle(m, path);
 	seq_putc(m, ' ');
 
 	/* file system type */
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -354,8 +354,11 @@ static const struct inode_operations pro
 };
 
 extern struct seq_operations mounts_op;
+
+/* Keep in sync with fs/namespace.c! */
 struct proc_mounts {
 	struct seq_file m;
+	void *page;
 	int event;
 };
 
@@ -383,12 +386,16 @@ static int __mounts_open(struct inode *i
 		p = kmalloc(sizeof(struct proc_mounts), GFP_KERNEL);
 		if (p) {
 			file->private_data = &p->m;
-			ret = seq_open(file, seq_ops);
+			p->page = (void *)__get_free_page(GFP_KERNEL);
+			if (p->page)
+				ret = seq_open(file, seq_ops);
 			if (!ret) {
 				p->m.private = ns;
 				p->event = ns->event;
 				return 0;
 			}
+			if (p->page)
+				free_page((unsigned long)p->page);
 			kfree(p);
 		}
 		put_mnt_ns(ns);
@@ -407,6 +414,7 @@ static int mounts_release(struct inode *
 		container_of(file->private_data, struct proc_mounts, m);
 	struct mnt_namespace *ns = p->m.private;
 
+	free_page((unsigned long)p->page);
 	put_mnt_ns(ns);
 	return seq_release(inode, file);
 }

-- 
Andreas Gruenbacher <agruen@suse.de>
SUSE Labs, SUSE LINUX Products GmbH
GF: Markus Rex, HRB 16746 (AG Nuernberg)

GPG: AF77 FAD1 1819 D442 400F  4BC8 409A 6903 4FDD EE02


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

* [d_path 7/7] Distinguish between connected and disconnected paths in d_path()
  2007-04-19 23:23             ` [d_path 0/7] Fixes to d_path: Respin Andreas Gruenbacher
                                 ` (5 preceding siblings ...)
  2007-04-19 23:23               ` [d_path 6/7] Filter out disconnected paths from /proc/mounts Andreas Gruenbacher
@ 2007-04-19 23:23               ` Andreas Gruenbacher
  2007-04-20  9:30               ` [d_path 0/7] Fixes to d_path: Respin Alan Cox
  7 siblings, 0 replies; 187+ messages in thread
From: Andreas Gruenbacher @ 2007-04-19 23:23 UTC (permalink / raw)
  To: Alan Cox
  Cc: jjohansen, linux-kernel, linux-security-module, linux-fsdevel,
	chrisw, Andrew Morton

[-- Attachment #1: fix-d_path.diff --]
[-- Type: text/plain, Size: 1614 bytes --]

Change d_path() so that it will never return a path starting with '/' if
the path doesn't lead up to the chroot directory. Also ensure that the
path returned never is the empty string: this would only occur with a lazily unmounted file system; return "." in that case instead.

Signed-off-by: Andreas Gruenbacher <agruen@suse.de>

---
 fs/dcache.c |   18 ++++--------------
 1 file changed, 4 insertions(+), 14 deletions(-)

--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1829,8 +1829,11 @@ global_root:
 			buffer++;
 			buflen++;
 		}
-		if (is_slash)
+		if (is_slash) {
+			if (*buffer == '\0')
+				*--buffer = '.';
 			goto out;
+		}
 	}
 	if (buflen < namelen)
 		goto Elong;
@@ -1843,18 +1846,6 @@ Elong:
 	goto out;
 }
 
-static char *__connect_d_path(char *path, char *buffer)
-{
-	if (!IS_ERR(path) && *path != '/') {
-		/* Pretend that disconnected paths are hanging off the root. */
-		if (path == buffer)
-			path = ERR_PTR(-ENAMETOOLONG);
-		else
-			*--path = '/';
-	}
-	return path;
-}
-
 /* write full pathname into buffer and return start of pathname */
 char *d_path(struct dentry *dentry, struct vfsmount *vfsmnt, char *buf,
 	     int buflen)
@@ -1868,7 +1859,6 @@ char *d_path(struct dentry *dentry, stru
 	root = dget(current->fs->root);
 	read_unlock(&current->fs->lock);
 	res = __d_path(dentry, vfsmnt, root, rootmnt, buf, buflen, 0);
-	res = __connect_d_path(res, buf);
 	dput(root);
 	mntput(rootmnt);
 	return res;

-- 
Andreas Gruenbacher <agruen@suse.de>
SUSE Labs, SUSE LINUX Products GmbH
GF: Markus Rex, HRB 16746 (AG Nuernberg)

GPG: AF77 FAD1 1819 D442 400F  4BC8 409A 6903 4FDD EE02


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

* Re: [d_path 0/7] Fixes to d_path: Respin
  2007-04-19 23:23             ` [d_path 0/7] Fixes to d_path: Respin Andreas Gruenbacher
                                 ` (6 preceding siblings ...)
  2007-04-19 23:23               ` [d_path 7/7] Distinguish between connected and disconnected paths in d_path() Andreas Gruenbacher
@ 2007-04-20  9:30               ` Alan Cox
  2007-04-20 11:45                 ` Andreas Gruenbacher
  7 siblings, 1 reply; 187+ messages in thread
From: Alan Cox @ 2007-04-20  9:30 UTC (permalink / raw)
  To: Andreas Gruenbacher
  Cc: jjohansen, linux-kernel, linux-security-module, linux-fsdevel,
	chrisw, Andrew Morton

> As far as I can see, glibc internally looks at /proc/mounts (or else mtab) to
> find out where tmpfs is mounted for opening files there, and to look up
> filesystem information for statfs(), while accessing that path, too. Fstatfs()
> also looks into the same files, but it only matches by filesystem type, so this
> is only a very unreliable heuristic, anyway.
> 
> So judging from that, glibc users should be fine.

So glibc does use it and you will change behaviour

> > I disagree - firstly because of not breaking stuff, and secondly because
> > it separates two discussions - merging AppArmor being one of them , and
> > the correct behaviour for getcwd & /proc/mounts being the other.
> 
> I agree with the separation of discussion argument. Here are patches that
> change getcwd() and /proc/mounts independent of the changes that AppArmor
> depends on.

More useful would be AppArmour without the changes to getcwd
and /proc/mounts

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

* Re: [d_path 1/7] Fix __d_path() for lazy unmounts and make it unambiguous
  2007-04-19 23:23               ` [d_path 1/7] Fix __d_path() for lazy unmounts and make it unambiguous Andreas Gruenbacher
@ 2007-04-20  9:32                 ` Alan Cox
  0 siblings, 0 replies; 187+ messages in thread
From: Alan Cox @ 2007-04-20  9:32 UTC (permalink / raw)
  To: Andreas Gruenbacher
  Cc: jjohansen, linux-kernel, linux-security-module, linux-fsdevel,
	chrisw, Andrew Morton

On Fri, 20 Apr 2007 01:23:04 +0200
Andreas Gruenbacher <agruen@suse.de> wrote:

> First, when __d_path() hits a lazily unmounted mount point, it tries to prepend
> the name of the lazily unmounted dentry to the path name.  It gets this wrong,
> and also overwrites the slash that separates the name from the following
> pathname component. This patch fixes that; if a process was in directory
> /foo/bar and /foo got lazily unmounted, the old result was ``foobar'' (note the
> missing slash), while the new result with this patch is ``foo/bar''.

ACK the fix

> of ``foobar'' in the example described above.  Subsequent patches propose to
> make getcwd() fail instead of reporting unreachable paths like this one and
> hide unreachable mount points from /proc/mounts.

NAK that change of behaviour on the following patches.

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

* Re: [d_path 6/7] Filter out disconnected paths from /proc/mounts
  2007-04-19 23:23               ` [d_path 6/7] Filter out disconnected paths from /proc/mounts Andreas Gruenbacher
@ 2007-04-20  9:34                 ` Alan Cox
  0 siblings, 0 replies; 187+ messages in thread
From: Alan Cox @ 2007-04-20  9:34 UTC (permalink / raw)
  To: Andreas Gruenbacher
  Cc: jjohansen, linux-kernel, linux-security-module, linux-fsdevel,
	chrisw, Andrew Morton

> There is some disagreement what /proc/mounts should include. Currently it
> reports all mounts from the current namespace and doesn't include lazy
> unmounts. This leads to ambiguities with the rootfs (which is an internal mount
> irrelevant to user-space except in the initrd), and in chroots.
> 
> With this and the next patch, /proc/mounts only reports the mounts reachable
> for the current process, which makes a lot more sense IMO.  If the current
> process is rooted in the namespace root (which it usually is), it will see all
> mounts except for the rootfs.
> 
> Signed-off-by: Andreas Gruenbacher <agruen@suse.de>

This change in behaviour appears to be fine for glibc (except when trying
to find the name of a file from a namespace we are not in, which wouldn't
have come out right before either)

Acked-by: Alan Cox <alan@redhat.com>

(but still NAK on the getcwd change)

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

* Re: [d_path 0/7] Fixes to d_path: Respin
  2007-04-20  9:30               ` [d_path 0/7] Fixes to d_path: Respin Alan Cox
@ 2007-04-20 11:45                 ` Andreas Gruenbacher
  2007-04-20 15:15                   ` Ulrich Drepper
  0 siblings, 1 reply; 187+ messages in thread
From: Andreas Gruenbacher @ 2007-04-20 11:45 UTC (permalink / raw)
  To: Alan Cox
  Cc: jjohansen, linux-kernel, linux-security-module, linux-fsdevel,
	chrisw, Andrew Morton

On Friday 20 April 2007 11:30, Alan Cox wrote:
> > As far as I can see, glibc internally looks at /proc/mounts (or else
> > mtab) to find out where tmpfs is mounted for opening files there, and to
> > look up filesystem information for statfs(), while accessing that path,
> > too. Fstatfs() also looks into the same files, but it only matches by
> > filesystem type, so this is only a very unreliable heuristic, anyway.
> >
> > So judging from that, glibc users should be fine.
>
> So glibc does use it and you will change behaviour

Not for statfs(), shm_open(), and sem_open().

Possibly for fstatfs(): fstatfs() has no way of looking up mount points per 
path name in /proc/mounts, and so it resorts to mapping from the numeric 
statfs->f_type to the filesystem name (e.g., "ext3"), looks up the first 
mount point with that name, and sets the statfs->f_flag flags based on that 
entry. This field may change from one arbitrary value to another.

Andreas

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

* Re: [d_path 0/7] Fixes to d_path: Respin
  2007-04-20 11:45                 ` Andreas Gruenbacher
@ 2007-04-20 15:15                   ` Ulrich Drepper
  2007-04-20 15:21                     ` Andreas Gruenbacher
  0 siblings, 1 reply; 187+ messages in thread
From: Ulrich Drepper @ 2007-04-20 15:15 UTC (permalink / raw)
  To: Andreas Gruenbacher
  Cc: Alan Cox, jjohansen, linux-kernel, linux-security-module,
	linux-fsdevel, chrisw, Andrew Morton

On 4/20/07, Andreas Gruenbacher <agruen@suse.de> wrote:
> Possibly for fstatfs(): fstatfs() has no way of looking up mount points per
> path name in /proc/mounts, and so it resorts to mapping from the numeric
> statfs->f_type to the filesystem name (e.g., "ext3"), looks up the first
> mount point with that name, and sets the statfs->f_flag flags based on that
> entry. This field may change from one arbitrary value to another.

What are you talking about?  fstatfs is a syscall, we do nothing but
copying values around at userlevel.

statvfs on the other hand does use /proc/mounts.  And it most
certainly does look at the mount point before looking at the
filesystem type.

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

* Re: [d_path 0/7] Fixes to d_path: Respin
  2007-04-20 15:15                   ` Ulrich Drepper
@ 2007-04-20 15:21                     ` Andreas Gruenbacher
  2007-04-20 15:24                       ` Ulrich Drepper
  0 siblings, 1 reply; 187+ messages in thread
From: Andreas Gruenbacher @ 2007-04-20 15:21 UTC (permalink / raw)
  To: Ulrich Drepper
  Cc: Alan Cox, jjohansen, linux-kernel, linux-security-module,
	linux-fsdevel, chrisw, Andrew Morton

On Friday 20 April 2007 17:15, Ulrich Drepper wrote:
> On 4/20/07, Andreas Gruenbacher <agruen@suse.de> wrote:
> > Possibly for fstatfs(): fstatfs() has no way of looking up mount points
> > per path name in /proc/mounts, and so it resorts to mapping from the
> > numeric statfs->f_type to the filesystem name (e.g., "ext3"), looks up
> > the first mount point with that name, and sets the statfs->f_flag flags
> > based on that entry. This field may change from one arbitrary value to
> > another.
>
> What are you talking about?  fstatfs is a syscall, we do nothing but
> copying values around at userlevel.
>
> statvfs on the other hand does use /proc/mounts.  And it most
> certainly does look at the mount point before looking at the
> filesystem type.

Yes, that one, sorry. The values it obtains that way are not reliable.

Thanks,
Andreas

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

* Re: [d_path 0/7] Fixes to d_path: Respin
  2007-04-20 15:21                     ` Andreas Gruenbacher
@ 2007-04-20 15:24                       ` Ulrich Drepper
  2007-04-20 16:40                         ` Andreas Gruenbacher
  0 siblings, 1 reply; 187+ messages in thread
From: Ulrich Drepper @ 2007-04-20 15:24 UTC (permalink / raw)
  To: Andreas Gruenbacher
  Cc: Alan Cox, jjohansen, linux-kernel, linux-security-module,
	linux-fsdevel, chrisw, Andrew Morton

On 4/20/07, Andreas Gruenbacher <agruen@suse.de> wrote:
> Yes, that one, sorry. The values it obtains that way are not reliable.

Why should the mount point info together with the filesystem type not
be reliable?  You're trying to find an excuse to break tings, that
seems all there is.

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

* Re: [d_path 0/7] Fixes to d_path: Respin
  2007-04-20 15:24                       ` Ulrich Drepper
@ 2007-04-20 16:40                         ` Andreas Gruenbacher
  2007-04-20 19:17                           ` Ulrich Drepper
  0 siblings, 1 reply; 187+ messages in thread
From: Andreas Gruenbacher @ 2007-04-20 16:40 UTC (permalink / raw)
  To: Ulrich Drepper
  Cc: Alan Cox, jjohansen, linux-kernel, linux-security-module,
	linux-fsdevel, chrisw, Andrew Morton

On Friday 20 April 2007 17:24, Ulrich Drepper wrote:
> On 4/20/07, Andreas Gruenbacher <agruen@suse.de> wrote:
> > Yes, that one, sorry. The values it obtains that way are not reliable.
>
> Why should the mount point info together with the filesystem type not
> be reliable?

Ah ... I overlooked that fstatvfs() also checks the device number, not only 
the name, and so then it can find the right device from that.

So for how glibc uses /proc/mounts in fstatvfs(), hiding unreachable mount 
points from /proc/mounts wouldn't improve things. The heuristic already 
doesn't work for file descriptors from other namespaces, so it's already 
broken unfortunately. A more robust mechanism for glibc to use would be nice; 
not sure it would be worth it only for fstatvfs though.

The code also seems to stop at the first matching mount point. You can have 
the same device mounted on the same mount point multiple times but with 
different mount options, e.g.,

	$ dd if=/dev/zero of=/var/tmp/ext2 bs=4096 count=16384
	$ mkfs.ext2 -F /var/tmp/ext2
	$ mount -o loop /var/tmp/ext2 /mnt
	$ mount -o loop,ro /var/tmp/ext2 /mnt
	$ tail -n 2 /proc/mounts
	/dev/loop0 /mnt ext2 rw 0 0
	/dev/loop1 /mnt ext2 ro 0 0

The topmost mount point appears last in /proc/mounts, and so unless I am 
overlooking something else, that's another minor problem.

The third problem, as I already tried to argue several times now, is that the 
mount points path that /proc/mounts reports may or may not actually exist. 
That's a problem for glibc, and you should be one of the first to notice and 
acknowledge that. I gave a chroot example that showed that in the current 
implementation, you can get pretty random clashes between mounts; there are 
other cases with lazy unmounts as well.

> You're trying to find an excuse to break tings, that seems all there is.

Now what makes you think that??

Andreas

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

* Re: [d_path 0/7] Fixes to d_path: Respin
  2007-04-20 16:40                         ` Andreas Gruenbacher
@ 2007-04-20 19:17                           ` Ulrich Drepper
  2007-04-20 20:44                             ` Miklos Szeredi
  2007-04-21 19:04                             ` Andreas Gruenbacher
  0 siblings, 2 replies; 187+ messages in thread
From: Ulrich Drepper @ 2007-04-20 19:17 UTC (permalink / raw)
  To: Andreas Gruenbacher
  Cc: Alan Cox, jjohansen, linux-kernel, linux-security-module,
	linux-fsdevel, chrisw, Andrew Morton

On 4/20/07, Andreas Gruenbacher <agruen@suse.de> wrote:
> The code also seems to stop at the first matching mount point. You can have
> the same device mounted on the same mount point multiple times but with
> different mount options, e.g., [...]

You can unfortunately do many stupid things.  That's the user's
problem.  The point is that everything works fine in an environment
which does not have such bogus mounts.  Namespaces are also the
problem of somebody else.  The people who came up with them didn't
think about the ramifications.  None of these problems can be
reasonably and reliably fixed with more support from the kernel.


> I gave a chroot example that showed that in the current
> implementation, you can get pretty random clashes between mounts; there are
> other cases with lazy unmounts as well.

Irrelevant as well.  If you create chroot problems it's your problem.

The fact is that if you have a normal setup the code works fine.  All
other situations cannot be handled with the current kernel interface.

This does not give anybody the right to say "since the code doesn't
always work we can break it completely".  That's completely
unacceptable.

If you want to improve the situation, do it.  Provide a solution for
the problems we are having in implementing statvfs.  Then we can talk
about stopping to use /proc/mounts for statvfs and you can change it
in a way which would harm the old implementation.  That's *my* view,
but I know there will be lots of people who would even object to that.
 The /proc filesystem is part of the kernel API and cannot be lightly
broken.

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

* Re: [d_path 0/7] Fixes to d_path: Respin
  2007-04-20 19:17                           ` Ulrich Drepper
@ 2007-04-20 20:44                             ` Miklos Szeredi
  2007-04-21 19:04                             ` Andreas Gruenbacher
  1 sibling, 0 replies; 187+ messages in thread
From: Miklos Szeredi @ 2007-04-20 20:44 UTC (permalink / raw)
  To: drepper
  Cc: agruen, alan, jjohansen, linux-kernel, linux-security-module,
	linux-fsdevel, chrisw, akpm

> > I gave a chroot example that showed that in the current
> > implementation, you can get pretty random clashes between mounts; there are
> > other cases with lazy unmounts as well.
> 
> Irrelevant as well.  If you create chroot problems it's your problem.
> 
> The fact is that if you have a normal setup the code works fine.  All
> other situations cannot be handled with the current kernel interface.
> 
> This does not give anybody the right to say "since the code doesn't
> always work we can break it completely".  That's completely
> unacceptable.

I'm not sure I understand the situation completely.  What exactly is
broken in libc by removing unreachable mounts from /proc/mounts?

Is it the situation when
 - file descriptor is opened
 - process does chroot
 - process does fstatvfs on file descriptor
?

In that case currently fstatvfs() _usually_ gives the correct results,
but can give wrong results if mounts paths accidently clash in
/proc/mounts?

Also isn't it the case, that fstatvfs() or statvfs() performed within
the chroot could also give incorrect result for a _reachable_ mount if
it clashes with an unreachable mount?

If this is the case, I would think that removing the unreachable
mounts from /proc/mounts, would actually be fixing this second case,
which is more likely to be used anyway.

BTW, this patch, or at least a predecessor is in -mm, and it very much
feels the Right Thing(tm).  The /proc/mounts under a chroot
environment actually looks sane, instead of some random crap, that it
was previously.

While we should make every effort to keep the kernel interfaces
stable, this shouldn't prevent us from fixing bugs.  And this one is
clearly a bug, even if not a very serious one.

Miklos

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

* Re: [d_path 3/7] Add d_namespace_path() to compute namespace relative pathnames
  2007-04-19 23:23               ` [d_path 3/7] Add d_namespace_path() to compute namespace relative pathnames Andreas Gruenbacher
@ 2007-04-21 12:57                 ` Tetsuo Handa
  2007-04-21 16:16                   ` Andreas Gruenbacher
  0 siblings, 1 reply; 187+ messages in thread
From: Tetsuo Handa @ 2007-04-21 12:57 UTC (permalink / raw)
  To: agruen
  Cc: alan, jjohansen, linux-kernel, linux-security-module,
	linux-fsdevel, chrisw, akpm

Hello.

I've just returned from ELC2007 and
I haven't read all posts in this thread yet,
but I want to comment to this function.

> In AppArmor, we are interested in pathnames relative to the namespace root.
> This is the same as d_path() except for the root where the search ends. Add
> a function for computing the namespace-relative path.
Yes. You came to the same conclusion as TOMOYO Linux does.
http://tomoyo.sourceforge.jp/cgi-bin/lxr/source/fs/realpath.c#L39


TOMOYO Linux uses pathnames relative to the namespace root.
You do this using d_path()'s way, but there needs some extensions
if you want to use d_namespace_path() for access control/auditing purpose.

In Linux, all characters other than NULL can be used in its pathname.
This means that you can't assume that whitespaces are delimiters.
For example, when you process entries in "Access ..... granted/rejected\n" format
(where ..... is a pathname and \n is a carriage return, like "Access /bin/ls granted\n"),
an entry "Access /bin/ls granted\nAccess /bin/cat granted\n" can be produced
if ..... is "/bin/ls granted\nAccess /bin/cat".
Processing such entry will produce wrong result.

Also, you want wildcards (usually "*") when doing pathname comparison,
but there are files that contains wildcards
(for example, "/usr/share/guile/1.6/ice-9/and-let*.scm" in CentOS 4.4).
You need to escape so that you can tell whether "*" indicates
a literal "*" or a wildcard.

Also, in non-English regions, characters that are out of ASCII printable range
are included in its pathname (for example, files created via Samba from Windows client).
Some programs can't handle characters that have MSB bit on,
so you may want to represent all characters without using MSB bit.

It may be OK if you use d_namespace_path() for processing a userland's configuration file,
but it is not OK if you use it for processing a kernel's configuration file.
The kernel has to be able to handle any characters.

So, you may want customized version of d_namespace_path()?

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

* Re: [d_path 3/7] Add d_namespace_path() to compute namespace relative pathnames
  2007-04-21 12:57                 ` Tetsuo Handa
@ 2007-04-21 16:16                   ` Andreas Gruenbacher
  0 siblings, 0 replies; 187+ messages in thread
From: Andreas Gruenbacher @ 2007-04-21 16:16 UTC (permalink / raw)
  To: Tetsuo Handa
  Cc: alan, jjohansen, linux-kernel, linux-security-module,
	linux-fsdevel, chrisw, akpm

On Saturday 21 April 2007 14:57, Tetsuo Handa wrote:
> So, you may want customized version of d_namespace_path()?

No. d_namespace_path() returns valid pathnames, just like d_path() does. 
Whatever quoting needed can be added to the resulting pathname.

Andreas

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

* Re: [d_path 0/7] Fixes to d_path: Respin
  2007-04-20 19:17                           ` Ulrich Drepper
  2007-04-20 20:44                             ` Miklos Szeredi
@ 2007-04-21 19:04                             ` Andreas Gruenbacher
  2007-04-21 19:46                               ` Ulrich Drepper
  2007-04-22  9:10                               ` Christoph Hellwig
  1 sibling, 2 replies; 187+ messages in thread
From: Andreas Gruenbacher @ 2007-04-21 19:04 UTC (permalink / raw)
  To: Ulrich Drepper
  Cc: Alan Cox, jjohansen, linux-kernel, linux-security-module,
	linux-fsdevel, chrisw, Andrew Morton

On Friday 20 April 2007 21:17, Ulrich Drepper wrote:
> On 4/20/07, Andreas Gruenbacher <agruen@suse.de> wrote:
> > The code also seems to stop at the first matching mount point. You can
> > have the same device mounted on the same mount point multiple times but
> > with different mount options, e.g., [...]
> 
> You can unfortunately do many stupid things.  That's the user's
> problem.  The point is that everything works fine in an environment
> which does not have such bogus mounts.

What I described is a supported feature, nothing more and nothing less. It's 
also relatively easy to handle this case correctly in glibc, e.g.,

--- a/sysdeps/unix/sysv/linux/internal_statvfs.c
+++ b/sysdeps/unix/sysv/linux/internal_statvfs.c
@@ -139,6 +139,7 @@ __statvfs_getflags (const char *name, in
 	      char *cp = mntbuf.mnt_opts;
 	      char *opt;
 
+	      result = 0;
 	      while ((opt = strsep (&cp, ",")) != NULL)
 		if (strcmp (opt, "ro") == 0)
 		  result |= ST_RDONLY;
@@ -157,9 +158,10 @@ __statvfs_getflags (const char *name, in
 		else if (strcmp (opt, "nodiratime") == 0)
 		  result |= ST_NODIRATIME;
 
-	      /* We can stop looking for more entries.  */
 	      success = true;
-	      break;
+	      /* Don't stop looking: the same device may be mounted several
+	         times with different options; in that case, the last entry
+		 is the topmost mount.  */
 	    }
 	}
       /* Maybe the kernel names for the filesystems changed or the

> > I gave a chroot example that showed that in the current implementation,
> > you can get pretty random clashes between mounts; there are other cases
> > with lazy unmounts as well. 
> 
> Irrelevant as well.  If you create chroot problems it's your problem.

There is no way to avoid these problems with chroots; it's not that anybody 
creates stupid problems on purpose.

The approach I'm proposing fixes these problems. It has a small disadvantage 
for statvfs / fstatvfs in some situations, which is due to the fact that the 
kernel doesn't offer a direct interface for querying the mount options of a 
file descriptor or path, and so glibc has to resort to messing 
with /proc/mounts. I don't see a nice way of fixing this without introducing 
[f]statvfs syscalls right now.

This is what POSIX says about statvfs / fstatvfs:
> It is unspecified whether all members of the statvfs structure have
> meaningful values on all file systems.

In my opinion, the advantage of not reporting bogus pathnames in /proc/mounts 
by far outweighs the problems is sometimes causes for fstatvfs(). Anyone 
relying on the information obtained from statvfs / fstatvfs is making false 
assumptions anyway, and in "normal setups" as you called them, nothing 
changes for fstatvfs and statvfs.

Andreas

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

* Re: [d_path 0/7] Fixes to d_path: Respin
  2007-04-21 19:04                             ` Andreas Gruenbacher
@ 2007-04-21 19:46                               ` Ulrich Drepper
  2007-04-22  9:10                               ` Christoph Hellwig
  1 sibling, 0 replies; 187+ messages in thread
From: Ulrich Drepper @ 2007-04-21 19:46 UTC (permalink / raw)
  To: Andreas Gruenbacher
  Cc: Alan Cox, linux-kernel, linux-security-module, linux-fsdevel,
	chrisw, Andrew Morton

On 4/21/07, Andreas Gruenbacher <agruen@suse.de> wrote:
> What I described is a supported feature, nothing more and nothing less. It's
> also relatively easy to handle this case correctly in glibc, e.g., [...]

This is only useful if the requirement of an ordered /proc/mounts is
part of the kernel ABI.  I.e., until somebody specifies (in the
sources, in kernel docs, I don't care where exactly) that the entries
in /proc/mounts appear in the order in which the mounts happened this
change is not better than the current code.  I have never found such
an assurance.


> This is what POSIX says about statvfs / fstatvfs:
> > It is unspecified whether all members of the statvfs structure have
> > meaningful values on all file systems.

Sure, just like POSIX in many other place leaves things unspecified.
This does not change the fact that we do a good job now.  You try to
use this wording to excuse the fact that you want to make the results
worse than they are now.  That's *not* the intend of this wording.


> In my opinion, the advantage of not reporting bogus pathnames in /proc/mounts
> by far outweighs the problems is sometimes causes for fstatvfs().

Hell no.  It is never acceptable to deliberately break compatibility.
Effects of bugs on the ABI might change but this is not the case here.
 This is an interface which forever displayed the information in this
form and it is correct and useful.

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

* Re: [d_path 0/7] Fixes to d_path: Respin
  2007-04-21 19:04                             ` Andreas Gruenbacher
  2007-04-21 19:46                               ` Ulrich Drepper
@ 2007-04-22  9:10                               ` Christoph Hellwig
  2007-04-22 15:48                                 ` Andreas Gruenbacher
  1 sibling, 1 reply; 187+ messages in thread
From: Christoph Hellwig @ 2007-04-22  9:10 UTC (permalink / raw)
  To: Andreas Gruenbacher
  Cc: Ulrich Drepper, Alan Cox, jjohansen, linux-kernel,
	linux-security-module, linux-fsdevel, chrisw, Andrew Morton

On Sat, Apr 21, 2007 at 09:04:06PM +0200, Andreas Gruenbacher wrote:
> > It is unspecified whether all members of the statvfs structure have
> > meaningful values on all file systems.
> 
> In my opinion, the advantage of not reporting bogus pathnames in /proc/mounts 
> by far outweighs the problems is sometimes causes for fstatvfs(). Anyone 
> relying on the information obtained from statvfs / fstatvfs is making false 
> assumptions anyway, and in "normal setups" as you called them, nothing 
> changes for fstatvfs and statvfs.

So what about stopping the flaming here and implementing real statvfs/
fstatvfs syscalls instead of these horrible hacks glibc has to do currently?
Using our kstatfs infrastructure that should be dirt simple.
arch/sparc64/solaris/fs.c already has a template of a statvfs syscall for
solaris, although we could probably improve a little on that.


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

* Re: [d_path 0/7] Fixes to d_path: Respin
  2007-04-22  9:10                               ` Christoph Hellwig
@ 2007-04-22 15:48                                 ` Andreas Gruenbacher
  0 siblings, 0 replies; 187+ messages in thread
From: Andreas Gruenbacher @ 2007-04-22 15:48 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: Ulrich Drepper, Alan Cox, jjohansen, linux-kernel,
	linux-security-module, linux-fsdevel, chrisw, Andrew Morton

[-- Attachment #1: Type: text/plain, Size: 1199 bytes --]

On Sunday 22 April 2007 11:10, Christoph Hellwig wrote:
> So what about stopping the flaming here and implementing real statvfs/
> fstatvfs syscalls instead of these horrible hacks glibc has to do
> currently?

I could imagine two approaches to that: either add statvfs and fstatvfs 
syscalls, or use one of the reserved fields in struct statfs, and return the 
missing flags in there.

Here is a very rough shot at the latter (i386 and x86_64 only so far). One of 
the uglinesses with that is that all those flags could be cleared at the same 
time, and so we can't tell whether the field is used from the flags alone and 
need some other mechanism like an extra bit, or a successive field that is 
guaranteed to be nonzero. Not sure whether that's acceptable considering the 
alternative of adding two syscalls and duplicating all the ugly compatibility 
scaffolding.

struct statvfs also defines a f_favail field, the ``number of file serial 
numbers available to non-privileged process''. Glibc currently sets this to 
the same value as f_ffree, the ``total number of free file serial numbers''. 
We don't seem to have this information, so adding this field wouldn't help 
immediately.

Andreas

[-- Attachment #2: statvfs.diff --]
[-- Type: text/x-diff, Size: 10761 bytes --]

---
 fs/compat.c                  |   13 +++++-----
 fs/ecryptfs/super.c          |    5 +++-
 fs/nfsd/nfs4xdr.c            |    2 -
 fs/nfsd/vfs.c                |    2 -
 fs/open.c                    |   53 ++++++++++++++++++++++++++++++++++---------
 fs/super.c                   |    2 -
 include/asm-generic/statfs.h |    9 ++++---
 include/asm-x86_64/compat.h  |    3 +-
 include/asm-x86_64/statfs.h  |    9 ++++---
 include/linux/fs.h           |    2 -
 include/linux/statfs.h       |   13 +++++++++-
 kernel/acct.c                |    2 -
 12 files changed, 84 insertions(+), 31 deletions(-)

--- a/fs/compat.c
+++ b/fs/compat.c
@@ -194,7 +194,7 @@ static int put_compat_statfs(struct comp
 	    __put_user(kbuf->f_fsid.val[0], &ubuf->f_fsid.val[0]) ||
 	    __put_user(kbuf->f_fsid.val[1], &ubuf->f_fsid.val[1]) ||
 	    __put_user(kbuf->f_frsize, &ubuf->f_frsize) ||
-	    __put_user(0, &ubuf->f_spare[0]) || 
+	    __put_user(kbuf->f_flag, &ubuf->f_flag) ||
 	    __put_user(0, &ubuf->f_spare[1]) || 
 	    __put_user(0, &ubuf->f_spare[2]) || 
 	    __put_user(0, &ubuf->f_spare[3]) || 
@@ -215,7 +215,7 @@ asmlinkage long compat_sys_statfs(const 
 	error = user_path_walk(path, &nd);
 	if (!error) {
 		struct kstatfs tmp;
-		error = vfs_statfs(nd.dentry, &tmp);
+		error = vfs_statfs(nd.dentry, nd.mnt, &tmp);
 		if (!error)
 			error = put_compat_statfs(buf, &tmp);
 		path_release(&nd);
@@ -233,7 +233,7 @@ asmlinkage long compat_sys_fstatfs(unsig
 	file = fget(fd);
 	if (!file)
 		goto out;
-	error = vfs_statfs(file->f_path.dentry, &tmp);
+	error = vfs_statfs(file->f_path.dentry, file->f_path.mnt, &tmp);
 	if (!error)
 		error = put_compat_statfs(buf, &tmp);
 	fput(file);
@@ -267,7 +267,8 @@ static int put_compat_statfs64(struct co
 	    __put_user(kbuf->f_namelen, &ubuf->f_namelen) ||
 	    __put_user(kbuf->f_fsid.val[0], &ubuf->f_fsid.val[0]) ||
 	    __put_user(kbuf->f_fsid.val[1], &ubuf->f_fsid.val[1]) ||
-	    __put_user(kbuf->f_frsize, &ubuf->f_frsize))
+	    __put_user(kbuf->f_frsize, &ubuf->f_frsize) ||
+	    __put_user(kbuf->f_flag, &ubuf->f_flag))
 		return -EFAULT;
 	return 0;
 }
@@ -283,7 +284,7 @@ asmlinkage long compat_sys_statfs64(cons
 	error = user_path_walk(path, &nd);
 	if (!error) {
 		struct kstatfs tmp;
-		error = vfs_statfs(nd.dentry, &tmp);
+		error = vfs_statfs(nd.dentry, nd.mnt, &tmp);
 		if (!error)
 			error = put_compat_statfs64(buf, &tmp);
 		path_release(&nd);
@@ -304,7 +305,7 @@ asmlinkage long compat_sys_fstatfs64(uns
 	file = fget(fd);
 	if (!file)
 		goto out;
-	error = vfs_statfs(file->f_path.dentry, &tmp);
+	error = vfs_statfs(file->f_path.dentry, file->f_path.mnt, &tmp);
 	if (!error)
 		error = put_compat_statfs64(buf, &tmp);
 	fput(file);
--- a/fs/ecryptfs/super.c
+++ b/fs/ecryptfs/super.c
@@ -119,7 +119,10 @@ static void ecryptfs_put_super(struct su
  */
 static int ecryptfs_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
-	return vfs_statfs(ecryptfs_dentry_to_lower(dentry), buf);
+	struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
+	struct vfsmount *lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry);
+
+	return vfs_statfs(lower_dentry, lower_mnt, buf);
 }
 
 /**
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -1457,7 +1457,7 @@ nfsd4_encode_fattr(struct svc_fh *fhp, s
 	if ((bmval0 & (FATTR4_WORD0_FILES_FREE | FATTR4_WORD0_FILES_TOTAL)) ||
 	    (bmval1 & (FATTR4_WORD1_SPACE_AVAIL | FATTR4_WORD1_SPACE_FREE |
 		       FATTR4_WORD1_SPACE_TOTAL))) {
-		err = vfs_statfs(dentry, &statfs);
+		err = vfs_statfs(dentry, exp->ex_mnt, &statfs);
 		if (err)
 			goto out_nfserr;
 	}
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -1767,7 +1767,7 @@ __be32
 nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct kstatfs *stat)
 {
 	__be32 err = fh_verify(rqstp, fhp, 0, MAY_NOP);
-	if (!err && vfs_statfs(fhp->fh_dentry,stat))
+	if (!err && vfs_statfs(fhp->fh_dentry, fhp->fh_export->ex_mnt, stat))
 		err = nfserr_io;
 	return err;
 }
--- a/fs/open.c
+++ b/fs/open.c
@@ -28,7 +28,7 @@
 #include <linux/rcupdate.h>
 #include <linux/audit.h>
 
-int vfs_statfs(struct dentry *dentry, struct kstatfs *buf)
+int vfs_statfs(struct dentry *dentry, struct vfsmount *mnt, struct kstatfs *buf)
 {
 	int retval = -ENODEV;
 
@@ -40,8 +40,35 @@ int vfs_statfs(struct dentry *dentry, st
 			if (retval)
 				return retval;
 			retval = dentry->d_sb->s_op->statfs(dentry, buf);
-			if (retval == 0 && buf->f_frsize == 0)
-				buf->f_frsize = buf->f_bsize;
+			if (retval == 0) {
+				unsigned long f_flag = ST_IN_USE;
+				unsigned long x;
+
+				if (buf->f_frsize == 0)
+					buf->f_frsize = buf->f_bsize;
+
+				x = dentry->d_inode->i_sb->s_flags;
+				if (x & MS_RDONLY)
+					f_flag |= ST_RDONLY;
+				if (x & MS_SYNCHRONOUS)
+					f_flag |= ST_SYNCHRONOUS;
+				if (x & MS_MANDLOCK)
+					f_flag |= ST_MANDLOCK;
+
+				if (mnt) {
+					int x = mnt->mnt_flags;
+
+					if (x & MNT_NOSUID)
+						f_flag |= ST_NOSUID;
+					if (x & MNT_NODEV)
+						f_flag |= ST_NODEV;
+					if (x & MNT_NOATIME)
+						f_flag |= ST_NOATIME;
+					if (x & MNT_NODIRATIME)
+						f_flag |= ST_NODIRATIME;
+				}
+				buf->f_flag = f_flag;
+			}
 		}
 	}
 	return retval;
@@ -49,12 +76,13 @@ int vfs_statfs(struct dentry *dentry, st
 
 EXPORT_SYMBOL(vfs_statfs);
 
-static int vfs_statfs_native(struct dentry *dentry, struct statfs *buf)
+static int vfs_statfs_native(struct dentry *dentry, struct vfsmount *mnt,
+			     struct statfs *buf)
 {
 	struct kstatfs st;
 	int retval;
 
-	retval = vfs_statfs(dentry, &st);
+	retval = vfs_statfs(dentry, mnt, &st);
 	if (retval)
 		return retval;
 
@@ -87,17 +115,19 @@ static int vfs_statfs_native(struct dent
 		buf->f_fsid = st.f_fsid;
 		buf->f_namelen = st.f_namelen;
 		buf->f_frsize = st.f_frsize;
+		buf->f_flag = st.f_flag;
 		memset(buf->f_spare, 0, sizeof(buf->f_spare));
 	}
 	return 0;
 }
 
-static int vfs_statfs64(struct dentry *dentry, struct statfs64 *buf)
+static int vfs_statfs64(struct dentry *dentry, struct vfsmount *mnt,
+			struct statfs64 *buf)
 {
 	struct kstatfs st;
 	int retval;
 
-	retval = vfs_statfs(dentry, &st);
+	retval = vfs_statfs(dentry, mnt, &st);
 	if (retval)
 		return retval;
 
@@ -114,6 +144,7 @@ static int vfs_statfs64(struct dentry *d
 		buf->f_fsid = st.f_fsid;
 		buf->f_namelen = st.f_namelen;
 		buf->f_frsize = st.f_frsize;
+		buf->f_flag = st.f_flag;
 		memset(buf->f_spare, 0, sizeof(buf->f_spare));
 	}
 	return 0;
@@ -127,7 +158,7 @@ asmlinkage long sys_statfs(const char __
 	error = user_path_walk(path, &nd);
 	if (!error) {
 		struct statfs tmp;
-		error = vfs_statfs_native(nd.dentry, &tmp);
+		error = vfs_statfs_native(nd.dentry, nd.mnt, &tmp);
 		if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
 			error = -EFAULT;
 		path_release(&nd);
@@ -146,7 +177,7 @@ asmlinkage long sys_statfs64(const char 
 	error = user_path_walk(path, &nd);
 	if (!error) {
 		struct statfs64 tmp;
-		error = vfs_statfs64(nd.dentry, &tmp);
+		error = vfs_statfs64(nd.dentry, nd.mnt, &tmp);
 		if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
 			error = -EFAULT;
 		path_release(&nd);
@@ -165,7 +196,7 @@ asmlinkage long sys_fstatfs(unsigned int
 	file = fget(fd);
 	if (!file)
 		goto out;
-	error = vfs_statfs_native(file->f_path.dentry, &tmp);
+	error = vfs_statfs_native(file->f_path.dentry, file->f_path.mnt, &tmp);
 	if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
 		error = -EFAULT;
 	fput(file);
@@ -186,7 +217,7 @@ asmlinkage long sys_fstatfs64(unsigned i
 	file = fget(fd);
 	if (!file)
 		goto out;
-	error = vfs_statfs64(file->f_path.dentry, &tmp);
+	error = vfs_statfs64(file->f_path.dentry, file->f_path.mnt, &tmp);
 	if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
 		error = -EFAULT;
 	fput(file);
--- a/fs/super.c
+++ b/fs/super.c
@@ -542,7 +542,7 @@ asmlinkage long sys_ustat(unsigned dev, 
         s = user_get_super(new_decode_dev(dev));
         if (s == NULL)
                 goto out;
-	err = vfs_statfs(s->s_root, &sbuf);
+	err = vfs_statfs(s->s_root, NULL, &sbuf);
 	drop_super(s);
 	if (err)
 		goto out;
--- a/include/asm-generic/statfs.h
+++ b/include/asm-generic/statfs.h
@@ -17,7 +17,8 @@ struct statfs {
 	__kernel_fsid_t f_fsid;
 	__u32 f_namelen;
 	__u32 f_frsize;
-	__u32 f_spare[5];
+	__u32 f_flag;
+	__u32 f_spare[4];
 };
 
 struct statfs64 {
@@ -31,7 +32,8 @@ struct statfs64 {
 	__kernel_fsid_t f_fsid;
 	__u32 f_namelen;
 	__u32 f_frsize;
-	__u32 f_spare[5];
+	__u32 f_flag;
+	__u32 f_spare[4];
 };
 
 struct compat_statfs64 {
@@ -45,7 +47,8 @@ struct compat_statfs64 {
 	__kernel_fsid_t f_fsid;
 	__u32 f_namelen;
 	__u32 f_frsize;
-	__u32 f_spare[5];
+	__u32 f_flag;
+	__u32 f_spare[4];
 };
 
 #endif
--- a/include/asm-x86_64/compat.h
+++ b/include/asm-x86_64/compat.h
@@ -104,7 +104,8 @@ struct compat_statfs {
 	compat_fsid_t	f_fsid;
 	int		f_namelen;	/* SunOS ignores this field. */
 	int		f_frsize;
-	int		f_spare[5];
+	int		f_flag;
+	int		f_spare[4];
 };
 
 #define COMPAT_RLIM_OLD_INFINITY	0x7fffffff
--- a/include/asm-x86_64/statfs.h
+++ b/include/asm-x86_64/statfs.h
@@ -24,7 +24,8 @@ struct statfs {
 	__kernel_fsid_t f_fsid;
 	long f_namelen;
 	long f_frsize;
-	long f_spare[5];
+	long f_flag;
+	long f_spare[4];
 };
 
 struct statfs64 {
@@ -38,7 +39,8 @@ struct statfs64 {
 	__kernel_fsid_t f_fsid;
 	long f_namelen;
 	long f_frsize;
-	long f_spare[5];
+	long f_flag;
+	long f_spare[4];
 };
 
 struct compat_statfs64 {
@@ -52,7 +54,8 @@ struct compat_statfs64 {
 	__kernel_fsid_t f_fsid;
 	__u32 f_namelen;
 	__u32 f_frsize;
-	__u32 f_spare[5];
+	__u32 f_flag;
+	__u32 f_spare[4];
 } __attribute__((packed));
 
 #endif
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1408,7 +1408,7 @@ extern struct vfsmount *copy_tree(struct
 extern void mnt_set_mountpoint(struct vfsmount *, struct dentry *,
 				  struct vfsmount *);
 
-extern int vfs_statfs(struct dentry *, struct kstatfs *);
+extern int vfs_statfs(struct dentry *, struct vfsmount *, struct kstatfs *);
 
 /* /sys/fs */
 extern struct subsystem fs_subsys;
--- a/include/linux/statfs.h
+++ b/include/linux/statfs.h
@@ -16,7 +16,18 @@ struct kstatfs {
 	__kernel_fsid_t f_fsid;
 	long f_namelen;
 	long f_frsize;
-	long f_spare[5];
+	unsigned long f_flag;
+	long f_spare[4];
 };
 
+#define ST_RDONLY	1
+#define ST_NOSUID	2
+#define ST_NODEV	4
+#define ST_NOEXEC	8
+#define ST_SYNCHRONOUS	16
+#define ST_MANDLOCK	64
+#define ST_NOATIME	1024
+#define ST_NODIRATIME	2048
+#define ST_IN_USE	(1 << 31)
+
 #endif
--- a/kernel/acct.c
+++ b/kernel/acct.c
@@ -118,7 +118,7 @@ static int check_free_space(struct file 
 	spin_unlock(&acct_globals.lock);
 
 	/* May block */
-	if (vfs_statfs(file->f_path.dentry, &sbuf))
+	if (vfs_statfs(file->f_path.dentry, file->f_path.mnt, &sbuf))
 		return res;
 	suspend = sbuf.f_blocks * SUSPEND;
 	resume = sbuf.f_blocks * RESUME;

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

* Re: [nameidata 1/2] Don't pass NULL nameidata to vfs_create
  2007-04-16 16:21       ` Christoph Hellwig
  2007-04-16 16:40         ` Andreas Gruenbacher
@ 2007-05-11 15:59         ` Andreas Gruenbacher
  1 sibling, 0 replies; 187+ messages in thread
From: Andreas Gruenbacher @ 2007-05-11 15:59 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: jjohansen, linux-kernel, linux-security-module, linux-fsdevel,
	chrisw, Tony Jones

On Monday 16 April 2007 18:21, Christoph Hellwig wrote:
> On Mon, Apr 16, 2007 at 06:11:30PM +0200, Andreas Gruenbacher wrote:
> > On Thursday 12 April 2007 12:06, Christoph Hellwig wrote:
> > > Once again very strong NACK.  Every conditional passing of vfsmounts get 
> > > my veto.  As mentioned last time if you really want this send a patch
> > > series first that passed the vfsmount consistantly.
> > 
> > I don't consider it fair to NACK this patch just because some other part
> > of the kernel uses vfs_create() in the wrong way -- those are really
> > independent issues. The bug is not that hard to fix though; here is a
> > proposed patch on top of the other AppArmor patches.
> 
> Note that it's not just this particular hunk, all these kinds of conditional
> passing are wrong.

Yes, the vfs uses or passes through a NULL nameidata or vfsmount pointer and 
no intent information in several places:

 (1) vfs_create() is called with a NULL nameidata in two places,

 (2) lookup_one_len() and lookup_one_len_kern() pass a NULL nameidata to
     permission(), d_op->d_revalidate(), and i_op->lookup(),

 (3) file_permission() passes a NULL nameidata to permission().

 (4) permission() is directly called with NULL nameidata in some places, and

In general it is incorrect to use NULL nameidata or vfsmounts because then the
vfsmount->mnt_flags cannot be checked, and no intent information is available. 
Intents are an optional optimization for remote filesystems; we can simply 
ignore them for local filesystems. There are some cases where we are passing 
NULL which are real bugs, but there are also other cases in which the 
operations are not mount related: for example, filesystems like pipefs have 
the MS_NOUSER flag set which indicates that they cannot be mounted at all. On 
filesystems like sysfs, files are created and removed whether or not that 
filesystem is mounted.

The places where we should pass a proper nameidata / vfsmount but don't should 
be fixed. Those are long-standing issues in the vfs though, and at least some 
are not easy to correct. AppArmor is affected by some of the NULL vfsmount 
passing, and we found a few more problems when looking into this more 
closely, but most of that NULL passing doesn't affect AppArmor:

 * In some places, vfs functions are called without nameidata / vfsmount,
   followed by calling lsm hooks with a vfsmount. In those cases, the vfs
   functions cannot check the vfsmount flags, but the lsm hooks will still
   do the appropriate checks.

 * In the AppArmor security model, directory searching is always allowed, and
   the access check are done once the leaf dentry + vfsmount has been looked
   up. For example, granting write access to /var/tmp/foo in a profile is
   sufficient to allow that access; search access to /var and /var/tmp does
   not need to be specified. (The regular inode permission checks are of
   course still performed.)

 * For filesystems like nfsd, the concept of pathname based access control
   doesn't make sense because of properties of the protocol: there is no
   reliable mapping from an nfs file handle to a particular file; aliases
   to the same file cannot be distinguished. (The AppArmor techdoc [1]
   describes this in more detail.)

   Not allowing to confine nfsd by AppArmor doesn't hurt much: nfsd provides
   its own export access control mechanisms. Also, nfsd cannot really be
   confined in a secure way because of how it is implemented in the kernel.
   Gfs2 may have similar properties; I didn't actually look into the protocol.

So I propose to separate the vfs NULL nameidata / vfsmount passing discussion 
from the AppArmor discussion. I have no problem working on the vfs fixes -- 
we could some nice cleanups there -- but that really is independent of 
AppArmor.

We almost have the revised AppArmor patches ready. We'll include all the fixes 
that are truly necessary, and everything beyond that will be posted 
separately.

> But anyway, creating fake nameidata structures is not really helpful.
> If there is a nameidata passed people expect it to be complete, and
> if you pass them to an LSM people will e.g. try to look into lookup
> intents.

Splitting up nameidata helps somewhat here. In cases where we don't have 
intent information available we can zero out the intent flags, and so in the 
worst case, we won't get the intent optimizations.

Thanks,
Andreas

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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-04-12 10:12   ` [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook Al Viro
@ 2007-05-23 19:06     ` Andreas Gruenbacher
  2007-05-24  1:28       ` James Morris
  0 siblings, 1 reply; 187+ messages in thread
From: Andreas Gruenbacher @ 2007-05-23 19:06 UTC (permalink / raw)
  To: Al Viro
  Cc: jjohansen, linux-kernel, linux-security-module, linux-fsdevel,
	chrisw, Tony Jones

On Thursday 12 April 2007 12:12, Al Viro wrote:
> On Thu, Apr 12, 2007 at 02:08:10AM -0700, jjohansen@suse.de wrote:
> > This is needed for computing pathnames in the AppArmor LSM.
>
> Which is an argument against said LSM in current form.

The fundamental model of AppArmor is to perform access checks based on the 
location of a file in the filesystem namespace, i.e., the pathname, and this 
can only be done with both the dentry and vfsmount. My understanding was that 
there was agreement at the last kernel summit that pathname based approaches 
should be allowed.

> > -	error = security_inode_create(dir, dentry, mode);
> > +	error = security_inode_create(dir, dentry, nd ? nd->mnt : NULL, mode);
>
> is a clear sign that interface is wrong.

No. There are callers of vfs_create() that use a NULL nameidata, and that's 
what causes the problem here. Struct nameidata is pretty big, and so we don't 
want to allocate temporary nameidata objects all over the place. So to me the 
above NULL check seems the lesser evil.

One way to deal with the nameidata size problem is to split it up into one 
part for the real path lookups, and a much smaller part that only contains 
the dentry, vfsmount, and intent flags. This would allow to pass around the 
smaller nameidata much more consistently.

John has posted patches for that on May 14; subject [RFD Patch 0/4]. Feedback 
appreciated.

In several places, the NULL nameidata is wrong because we can't check the 
vfsmount flags or intent. Not having this information is causing problems for 
nfs too for example -- it's not an AppArmor specific problem.

> Leaving aside the general idiocy of "we prohibit to do something with file
> if mounted here, but if there's another mountpoint, well, we just miss", an
> API of that kind is just plain wrong.  Either you can live without seeing
> vfsmount in that method (in which case you shouldn't pass it at all), or you
> have a hole.

This is backwards from what AppArmor does. The policy defines which paths may 
be accessed; all paths not explicitly listed are denied. If files are mounted 
at multiple locations, then the policy may allow access to some locations but 
not to others. That's not a hole.

In fact this is not much different from traditional permissions on parent 
directories: even if the same files are mounted at several locations, parent 
directory permissions may allow accessing only some of those locations.

Thanks,
Andreas

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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-05-23 19:06     ` Andreas Gruenbacher
@ 2007-05-24  1:28       ` James Morris
  2007-05-24  9:16         ` Andreas Gruenbacher
                           ` (2 more replies)
  0 siblings, 3 replies; 187+ messages in thread
From: James Morris @ 2007-05-24  1:28 UTC (permalink / raw)
  To: Andreas Gruenbacher
  Cc: Al Viro, jjohansen, linux-kernel, linux-security-module,
	linux-fsdevel, chrisw, Tony Jones

On Wed, 23 May 2007, Andreas Gruenbacher wrote:

> This is backwards from what AppArmor does. The policy defines which paths may 
> be accessed; all paths not explicitly listed are denied. If files are mounted 
> at multiple locations, then the policy may allow access to some locations but 
> not to others. That's not a hole.

I don't know what else you'd call it.

Would you mind providing some concrete examples of how such a model would 
be useful?


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

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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-05-24  1:28       ` James Morris
@ 2007-05-24  9:16         ` Andreas Gruenbacher
  2007-05-24 12:51         ` [AppArmor 01/41] Pass struct vfsmount to the inode_create LSMhook Tetsuo Handa
       [not found]         ` <200705241112.41101.agruen@suse.de>
  2 siblings, 0 replies; 187+ messages in thread
From: Andreas Gruenbacher @ 2007-05-24  9:16 UTC (permalink / raw)
  To: James Morris
  Cc: Al Viro, jjohansen, linux-kernel, linux-security-module,
	linux-fsdevel, chrisw, Tony Jones

On Thursday 24 May 2007 03:28, James Morris wrote:
> On Wed, 23 May 2007, Andreas Gruenbacher wrote:
> > This is backwards from what AppArmor does. The policy defines which paths
> > may be accessed; all paths not explicitly listed are denied. If files are
> > mounted at multiple locations, then the policy may allow access to some
> > locations but not to others. That's not a hole.
>
> I don't know what else you'd call it.

AppArmor doesn't label files; it's a different model from SELinux. Its policy 
defines which processes may access which paths. Even if for some reson the 
same files were visible elsewhere, the policy wouldn't cover those other 
paths, and so accessing them would be denied. So again, that's not a security 
hole.

> Would you mind providing some concrete examples of how such a model would
> be useful?

The model is explained, with examples, in the technical documentation at 
http://forgeftp.novell.com//apparmor/LKML_Submission-May_07/.

Thanks,
Andreas

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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSMhook
  2007-05-24  1:28       ` James Morris
  2007-05-24  9:16         ` Andreas Gruenbacher
@ 2007-05-24 12:51         ` Tetsuo Handa
       [not found]         ` <200705241112.41101.agruen@suse.de>
  2 siblings, 0 replies; 187+ messages in thread
From: Tetsuo Handa @ 2007-05-24 12:51 UTC (permalink / raw)
  To: jmorris, agruen
  Cc: viro, jjohansen, linux-kernel, linux-security-module,
	linux-fsdevel, chrisw, tonyj

Hello.

I think bind mounts were discussed when shared subtree
( http://lwn.net/Articles/159092/ ) was introduced.

For systems that allow users mount their CD/DVDs freely,
bind mounts are used and labeling files is a convenient way
to deny accessing somebody else's files.

But systems that don't allow users mount their CD/DVDs freely,
bind mounts needn't to be used and using pathnames is a convenient way
to deny accessing somebody else's files.

Pathname based access control/auditing system
works if the system doesn't use bind mounts.

However, there are distributions (e.g. Debian Etch)
that always use bind mounts. In such distributions,
pathname based access control/auditing system doesn't work.

This is not the fault of distributions nor
pathname based access control/auditing system.
It is possible to solve by passing vfsmount to VFS and LSM functions.

SELinux users are having a lot of trouble because pathnames in audit logs
are not always complete.
AppArmor users are having a lot of trouble because pathnames which
a process requested are ambiguous when bind mounts are used.

Being able to report pathnames that a process requested is not surprising
when considering user friendliness.
I beleive passing vfsmount makes both users happy.

Thanks.

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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
       [not found]         ` <200705241112.41101.agruen@suse.de>
@ 2007-05-24 13:19           ` James Morris
  2007-05-24 18:10             ` Andreas Gruenbacher
  2007-05-25  8:01             ` Toshiharu Harada
  0 siblings, 2 replies; 187+ messages in thread
From: James Morris @ 2007-05-24 13:19 UTC (permalink / raw)
  To: Andreas Gruenbacher
  Cc: Al Viro, jjohansen, linux-kernel, linux-security-module,
	linux-fsdevel, chrisw, Tony Jones

On Thu, 24 May 2007, Andreas Gruenbacher wrote:

> > Would you mind providing some concrete examples of how such a model would
> > be useful?
> 
> The model is explained, with examples, in the technical documentation at http://forgeftp.novell.com//apparmor/LKML_Submission-May_07/.

I'm asking specifically about a model where you'd want to provide 
differing access to the same objects based on the pathname used for 
access to the objects, per:

  "If files are mounted at multiple locations, then the policy may allow 
   access to some locations but not to others.  That's not a hole."

I don't see specific examples of this kind of policy in that document, 
and the document seems to be saying quite the opposite -- that the AA 
policy is only valid in conjunction with further constraints on how the 
objects may be accessed:

Section 3.2:

 "Pathnames are meaningful only within a namespace. Each namespace has a 
  root where all the files, directories, and mount points are hanging off 
  from.

  The privilege of creating new namespaces is bound to the CAP_ SYS_ ADMIN 
  capability, which grants a multitude of other things that would allow a 
  process to break out of AppArmor confinement, so confined processes are 
  not supposed to have this privilege, and processes with this capability 
  need to be considered trusted. "


I can restate my question and ask why you'd want a security policy like:

  Subject 'sysadmin' has:
     read access to /etc/shadow
     read/write access to /views/sysadmin/etc/shadow

where the objects referenced by the paths are identical and visible to the 
subject along both paths, in keeping with your description of "policy may 
allow access to some locations but not to others" ?


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

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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-05-30  5:52                                   ` Crispin Cowan
@ 2007-05-24 14:40                                     ` Pavel Machek
  2007-05-30 10:06                                     ` Alan Cox
  1 sibling, 0 replies; 187+ messages in thread
From: Pavel Machek @ 2007-05-24 14:40 UTC (permalink / raw)
  To: Crispin Cowan
  Cc: Valdis.Kletnieks, Kyle Moffett, Toshiharu Harada, James Morris,
	casey, Andreas Gruenbacher, linux-kernel, linux-security-module,
	linux-fsdevel

Hi!

> >> Average users are not supposed to be writing security policy.  To be  
> >> honest, even average-level system administrators should not be  
> >> writing security policy.
> That explains so much! "SELinux: you're too dumb to use it, so just keep
> your hands in your pockets." :-)
> 
> AppArmor was designed to allow your average sys admin to write a
> security policy. It makes different design choices than SELinux to
> achieve that goal. As a result, AppArmor is an utter failure when
> compared to SELinux's goals, and SELinux in turn is an utter failure
> when compared to AppArmor's goals.

I'd not be that sure. SELinux can read AA config files, with some
performance problems and bad problems with new files.

I bet solving the 'new files' problem is not going to take 20% of AA's
size...
							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] 187+ messages in thread

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-05-30  1:46                                 ` David Wagner
@ 2007-05-24 14:47                                   ` Pavel Machek
  2007-06-01 17:44                                     ` Valdis.Kletnieks
  0 siblings, 1 reply; 187+ messages in thread
From: Pavel Machek @ 2007-05-24 14:47 UTC (permalink / raw)
  To: David Wagner; +Cc: linux-kernel

Hi!

(Please do not drop me from cc list when replying).

> > no, this won't help you much against local users, [...]
> 
> Pavel Machek  wrote:
> >Hmm, I guess I'd love "it is useless on multiuser boxes" to become
> >standard part of AA advertising.
> 
> That's not quite what david@ said.  As I understand it, AppArmor is not
> focused on preventing attacks by local users against other local users;
> that's not the main problem it is trying to solve.  Rather, it's primary
> purpose is to deal with attacks by remote bad guys against your network
> servers.  That is a laudable goal.

It is also not going to prevent local users attacking network servers.
Local users can ln arbitrary files, and then play tricks with network
servers.

> This means that AppArmor could still be useful on multiuser boxes,
> even if that utility is limited to defending (some) network daemons
> against remote attack (or, more precisely, reducing the damage done by
> a successful remote attack against a network daemon).


Yes, if there's significantly more remote bad guys than local bad
guys, and if remote bad guys can't just get some local user first, AA
still has some value.
							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] 187+ messages in thread

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-05-24 13:19           ` [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook James Morris
@ 2007-05-24 18:10             ` Andreas Gruenbacher
  2007-05-24 18:40               ` Al Viro
  2007-05-24 18:58               ` Casey Schaufler
  2007-05-25  8:01             ` Toshiharu Harada
  1 sibling, 2 replies; 187+ messages in thread
From: Andreas Gruenbacher @ 2007-05-24 18:10 UTC (permalink / raw)
  To: James Morris
  Cc: Al Viro, jjohansen, linux-kernel, linux-security-module,
	linux-fsdevel, chrisw, Tony Jones

On Thursday 24 May 2007 15:19, James Morris wrote:
> On Thu, 24 May 2007, Andreas Gruenbacher wrote:
> > > Would you mind providing some concrete examples of how such a model
> > > would be useful?
> >
> > The model is explained, with examples, in the technical documentation at
> > http://forgeftp.novell.com//apparmor/LKML_Submission-May_07/.
>
> I'm asking specifically about a model where you'd want to provide
> differing access to the same objects based on the pathname used for
> access to the objects, per:
>
>   "If files are mounted at multiple locations, then the policy may allow
>    access to some locations but not to others.  That's not a hole."
>
> I don't see specific examples of this kind of policy in that document,

I guess I see what you are getting at. If a user has read/write access 
to /views/sysadmin/etc/shadow and if that is an alias for /etc/shadow, then 
of course it doesn't help to give the user only read access to /etc/shadow to 
protect that file. So you can shoot yourself in the foot with mounts, and 
also with hardlinks. That's why confined processes are not allowed to mount 
stuff, and why hardlinks requires the appropriate profile permissions.

AppArmor depends on the namespace so it cares about namespace manipulations,  
just like SELinux depends on labels so labels matter there.

> and the document seems to be saying quite the opposite -- that the AA
> policy is only valid in conjunction with further constraints on how the
> objects may be accessed:

Read it like this: we don't have a good idea how to support multiple 
namespaces so far. Currently, we interpret all pathnames relative to the 
namespace a process is in. Confined processes don't have the privilege to 
create or manipulate namespaces, which makes this safe. We may find a better 
future solution.

> I can restate my question and ask why you'd want a security policy like:
>
>   Subject 'sysadmin' has:
>      read access to /etc/shadow
>      read/write access to /views/sysadmin/etc/shadow
>
> where the objects referenced by the paths are identical and visible to the
> subject along both paths, in keeping with your description of "policy may
> allow access to some locations but not to others" ?

I'm not aware of situations where giving different permissions to different  
paths to the same file would actually be useful. The security model doesn't  
prevent it though, and it's not a security hole.

Andreas

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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-05-24 18:10             ` Andreas Gruenbacher
@ 2007-05-24 18:40               ` Al Viro
  2007-05-24 21:56                 ` Andreas Gruenbacher
  2007-05-24 18:58               ` Casey Schaufler
  1 sibling, 1 reply; 187+ messages in thread
From: Al Viro @ 2007-05-24 18:40 UTC (permalink / raw)
  To: Andreas Gruenbacher
  Cc: James Morris, jjohansen, linux-kernel, linux-security-module,
	linux-fsdevel, chrisw, Tony Jones

On Thu, May 24, 2007 at 08:10:00PM +0200, Andreas Gruenbacher wrote:

> Read it like this: we don't have a good idea how to support multiple 
> namespaces so far. Currently, we interpret all pathnames relative to the 
> namespace a process is in. Confined processes don't have the privilege to 
> create or manipulate namespaces, which makes this safe. We may find a better 
> future solution.

You also don't have a solution for multiple chroot jails, since they
often have the same fs mounted in many places on given box *and* since
the pathnames from the confined processes' POVs have fsck-all to do
with each other.

It's really not kinder than multiple namespaces as far as your approach
is concerned.

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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-05-24 18:10             ` Andreas Gruenbacher
  2007-05-24 18:40               ` Al Viro
@ 2007-05-24 18:58               ` Casey Schaufler
  2007-05-25  4:14                 ` Andreas Gruenbacher
                                   ` (2 more replies)
  1 sibling, 3 replies; 187+ messages in thread
From: Casey Schaufler @ 2007-05-24 18:58 UTC (permalink / raw)
  To: Andreas Gruenbacher, James Morris
  Cc: linux-kernel, linux-security-module, linux-fsdevel


--- Andreas Gruenbacher <agruen@suse.de> wrote:

> > where the objects referenced by the paths are identical and visible to the
> > subject along both paths, in keeping with your description of "policy may
> > allow access to some locations but not to others" ?
> 
> I'm not aware of situations where giving different permissions to different  
> paths to the same file would actually be useful. The security model doesn't  
> prevent it though, and it's not a security hole.

On Fedora zcat, gzip and gunzip are all links to the same file.
I can imagine (although it is a bit of a stretch) allowing a set
of users access to gunzip but not gzip (or the other way around).
There are probably more sophisticated programs that have different
behavior based on the name they're invoked by that would provide
a more compelling arguement, assuming of course that you buy into
the behavior-based-on-name scheme. What I think I'm suggesting is
that AppArmor might be useful in addressing the fact that a file
with multiple hard links is necessarily constrained to have the
same access control on each of those names. That assumes one
believes that such behavior is flawwed, and I'm not going to try
to argue that. The question was about an example, and there is one.



Casey Schaufler
casey@schaufler-ca.com

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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-05-24 18:40               ` Al Viro
@ 2007-05-24 21:56                 ` Andreas Gruenbacher
  0 siblings, 0 replies; 187+ messages in thread
From: Andreas Gruenbacher @ 2007-05-24 21:56 UTC (permalink / raw)
  To: Al Viro
  Cc: James Morris, jjohansen, linux-kernel, linux-security-module,
	linux-fsdevel, chrisw, Tony Jones

On Thursday 24 May 2007 20:40, Al Viro wrote:
> On Thu, May 24, 2007 at 08:10:00PM +0200, Andreas Gruenbacher wrote:
> 
> > Read it like this: we don't have a good idea how to support multiple 
> > namespaces so far. Currently, we interpret all pathnames relative to the 
> > namespace a process is in. Confined processes don't have the privilege to 
> > create or manipulate namespaces, which makes this safe. We may find a
> > better future solution.
> 
> You also don't have a solution for multiple chroot jails, since they
> often have the same fs mounted in many places on given box *and* since
> the pathnames from the confined processes' POVs have fsck-all to do
> with each other.
>
> It's really not kinder than multiple namespaces as far as your approach
> is concerned.

Well, the pathnames we check against are namespace relative, so no matter what 
pathnames the chrooted processes think they are looking at, we always know 
the actual pathnames up to ``outside the chroot''. Having the same filesystem 
mounted in multiple chroots or in multiple locations in the same chroot 
doesn't matter.

The main problem I see when it comes to defining per-namespace policy is that 
namespaces are inherently anonymous, and there is no obvious way of 
associating different sets of profiles with different namespaces. 
Implementing something to also handle multiple namespaces doesn't seem 
hard -- after all, it's not such a difficult concept -- but I don't have a 
good enough idea what would work best.

Thanks,
Andreas

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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-05-24 18:58               ` Casey Schaufler
@ 2007-05-25  4:14                 ` Andreas Gruenbacher
  2007-05-25  5:17                 ` Jeremy Maitin-Shepard
  2007-05-26  5:20                 ` Kyle Moffett
  2 siblings, 0 replies; 187+ messages in thread
From: Andreas Gruenbacher @ 2007-05-25  4:14 UTC (permalink / raw)
  To: casey; +Cc: James Morris, linux-kernel, linux-security-module, linux-fsdevel

On Thursday 24 May 2007 20:58, Casey Schaufler wrote:
> On Fedora zcat, gzip and gunzip are all links to the same file.
> I can imagine (although it is a bit of a stretch) allowing a set
> of users access to gunzip but not gzip (or the other way around).
> There are probably more sophisticated programs that have different
> behavior based on the name they're invoked by that would provide
> a more compelling arguement, assuming of course that you buy into
> the behavior-based-on-name scheme. What I think I'm suggesting is
> that AppArmor might be useful in addressing the fact that a file
> with multiple hard links is necessarily constrained to have the
> same access control on each of those names. That assumes one
> believes that such behavior is flawwed, and I'm not going to try
> to argue that. The question was about an example, and there is one.

Different policy for different names of the same binary makes more obvious 
sense with chroot environments. That's slightly different from having 
different permissions for the same file within a single profile though.

Thanks,
Andreas

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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-05-24 18:58               ` Casey Schaufler
  2007-05-25  4:14                 ` Andreas Gruenbacher
@ 2007-05-25  5:17                 ` Jeremy Maitin-Shepard
  2007-05-25 17:43                   ` Casey Schaufler
  2007-05-26  5:20                 ` Kyle Moffett
  2 siblings, 1 reply; 187+ messages in thread
From: Jeremy Maitin-Shepard @ 2007-05-25  5:17 UTC (permalink / raw)
  To: Casey Schaufler
  Cc: Andreas Gruenbacher, James Morris, linux-kernel,
	linux-security-module, linux-fsdevel

Casey Schaufler <casey@schaufler-ca.com> writes:

> On Fedora zcat, gzip and gunzip are all links to the same file.
> I can imagine (although it is a bit of a stretch) allowing a set
> of users access to gunzip but not gzip (or the other way around).
> There are probably more sophisticated programs that have different
> behavior based on the name they're invoked by that would provide
> a more compelling arguement, assuming of course that you buy into
> the behavior-based-on-name scheme. What I think I'm suggesting is
> that AppArmor might be useful in addressing the fact that a file
> with multiple hard links is necessarily constrained to have the
> same access control on each of those names. That assumes one
> believes that such behavior is flawwed, and I'm not going to try
> to argue that. The question was about an example, and there is one.

This doesn't work.  The behavior depends on argv[0], which is not
necessarily the same as the name of the file.

-- 
Jeremy Maitin-Shepard

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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-05-24 13:19           ` [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook James Morris
  2007-05-24 18:10             ` Andreas Gruenbacher
@ 2007-05-25  8:01             ` Toshiharu Harada
  1 sibling, 0 replies; 187+ messages in thread
From: Toshiharu Harada @ 2007-05-25  8:01 UTC (permalink / raw)
  To: James Morris
  Cc: Andreas Gruenbacher, Al Viro, jjohansen, linux-kernel,
	linux-security-module, linux-fsdevel, chrisw, Tony Jones

Hi,

2007/5/24, James Morris <jmorris@namei.org>:
> I can restate my question and ask why you'd want a security policy like:
>
>  Subject 'sysadmin' has:
>     read access to /etc/shadow
>     read/write access to /views/sysadmin/etc/shadow
>
> where the objects referenced by the paths are identical and visible to the
> subject along both paths, in keeping with your description of "policy may
> allow access to some locations but not to others" ?

If I understand correctly, the original issue was whether to allow passing
vfsmount to the inode_create LSM hook or not. Which is independent from
AA or "pathname based MAC", I think.

It is proven that Linux can be used without that change, however it is
also clear that current LSM cause the ambiguities as AA people has
explained. Clearing ambiguities is a obvious gain to Linux and will make
benefits for auditing besides "pathname based MAC".

So here's my opinion. If anybody can't explain clear reason (or needs)
to keep these ambiguities unsolved, we should consider to merge
the proposal.

Thanks.

-- 
Toshiharu Harada
haradats@gmail.com

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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-05-25  5:17                 ` Jeremy Maitin-Shepard
@ 2007-05-25 17:43                   ` Casey Schaufler
  2007-05-25 18:10                     ` Jeremy Maitin-Shepard
  2007-05-25 20:00                     ` Andreas Gruenbacher
  0 siblings, 2 replies; 187+ messages in thread
From: Casey Schaufler @ 2007-05-25 17:43 UTC (permalink / raw)
  To: Jeremy Maitin-Shepard
  Cc: Andreas Gruenbacher, James Morris, linux-kernel,
	linux-security-module, linux-fsdevel


--- Jeremy Maitin-Shepard <jbms@cmu.edu> wrote:

> Casey Schaufler <casey@schaufler-ca.com> writes:
> 
> > On Fedora zcat, gzip and gunzip are all links to the same file.
> > I can imagine (although it is a bit of a stretch) allowing a set
> > of users access to gunzip but not gzip (or the other way around).
> > There are probably more sophisticated programs that have different
> > behavior based on the name they're invoked by that would provide
> > a more compelling arguement, assuming of course that you buy into
> > the behavior-based-on-name scheme. What I think I'm suggesting is
> > that AppArmor might be useful in addressing the fact that a file
> > with multiple hard links is necessarily constrained to have the
> > same access control on each of those names. That assumes one
> > believes that such behavior is flawwed, and I'm not going to try
> > to argue that. The question was about an example, and there is one.
> 
> This doesn't work.  The behavior depends on argv[0], which is not
> necessarily the same as the name of the file.

Sorry, but I don't understand your objection. If AppArmor is configured
to allow everyone access to /bin/gzip but only some people access to
/bin/gunzip and (important detail) the single binary uses argv[0]
as documented and (another important detail) there aren't other links
named gunzip to the binary (ok, that's lots of if's) you should be fine.
I suppose you could make a shell that lies to exec, but the AppArmor
code could certainly check for that in exec by enforcing the argv[0]
convention. It would be perfectly reasonable for a system that is so
dependent on pathnames to require that.


Casey Schaufler
casey@schaufler-ca.com

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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-05-25 17:43                   ` Casey Schaufler
@ 2007-05-25 18:10                     ` Jeremy Maitin-Shepard
  2007-05-25 18:13                       ` Jeremy Maitin-Shepard
  2007-05-25 19:06                       ` Casey Schaufler
  2007-05-25 20:00                     ` Andreas Gruenbacher
  1 sibling, 2 replies; 187+ messages in thread
From: Jeremy Maitin-Shepard @ 2007-05-25 18:10 UTC (permalink / raw)
  To: casey
  Cc: Andreas Gruenbacher, James Morris, linux-kernel,
	linux-security-module, linux-fsdevel

Casey Schaufler <casey@schaufler-ca.com> writes:

> --- Jeremy Maitin-Shepard <jbms@cmu.edu> wrote:
>> Casey Schaufler <casey@schaufler-ca.com> writes:
>> 
>> > On Fedora zcat, gzip and gunzip are all links to the same file.
>> > I can imagine (although it is a bit of a stretch) allowing a set
>> > of users access to gunzip but not gzip (or the other way around).
>> > There are probably more sophisticated programs that have different
>> > behavior based on the name they're invoked by that would provide
>> > a more compelling arguement, assuming of course that you buy into
>> > the behavior-based-on-name scheme. What I think I'm suggesting is
>> > that AppArmor might be useful in addressing the fact that a file
>> > with multiple hard links is necessarily constrained to have the
>> > same access control on each of those names. That assumes one
>> > believes that such behavior is flawwed, and I'm not going to try
>> > to argue that. The question was about an example, and there is one.
>> 
>> This doesn't work.  The behavior depends on argv[0], which is not
>> necessarily the same as the name of the file.

> Sorry, but I don't understand your objection. If AppArmor is configured
> to allow everyone access to /bin/gzip but only some people access to
> /bin/gunzip and (important detail) the single binary uses argv[0]
> as documented and (another important detail) there aren't other links
> named gunzip to the binary (ok, that's lots of if's) you should be fine.
> I suppose you could make a shell that lies to exec, but the AppArmor
> code could certainly check for that in exec by enforcing the argv[0]
> convention. It would be perfectly reasonable for a system that is so
> dependent on pathnames to require that.

Well, my point was exactly that App Armor doesn't (as far as I know) do
anything to enforce the argv[0] convention, nor would it in general
prevent a confined program from making a symlink or hard link.  Even
disregarding that, it seems very fragile in general to make an suid
program (there would be no point in confining the execution of a
non-suid program) perform essentially access control based on argv[0].

-- 
Jeremy Maitin-Shepard

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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-05-25 18:10                     ` Jeremy Maitin-Shepard
@ 2007-05-25 18:13                       ` Jeremy Maitin-Shepard
  2007-05-25 19:06                       ` Casey Schaufler
  1 sibling, 0 replies; 187+ messages in thread
From: Jeremy Maitin-Shepard @ 2007-05-25 18:13 UTC (permalink / raw)
  To: casey
  Cc: Andreas Gruenbacher, James Morris, linux-kernel,
	linux-security-module, linux-fsdevel

Jeremy Maitin-Shepard <jbms@cmu.edu> writes:

> [snip]

> Well, my point was exactly that App Armor doesn't (as far as I know) do
> anything to enforce the argv[0] convention, nor would it in general
> prevent a confined program from making a symlink or hard link.  Even
> disregarding that, it seems very fragile in general to make an suid
> program (there would be no point in confining the execution of a
> non-suid program) perform essentially access control based on argv[0].

Note that by "confining the execution of a non-suid program", I mean
defining an App Armor profile that prevents the execution of a
particular non-suid program, unless of course the program file itself
contains secret information, which is irrelevant to this discussion.

-- 
Jeremy Maitin-Shepard

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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-05-25 18:10                     ` Jeremy Maitin-Shepard
  2007-05-25 18:13                       ` Jeremy Maitin-Shepard
@ 2007-05-25 19:06                       ` Casey Schaufler
  2007-05-26  1:40                         ` Tetsuo Handa
  2007-05-26 12:10                         ` Andreas Gruenbacher
  1 sibling, 2 replies; 187+ messages in thread
From: Casey Schaufler @ 2007-05-25 19:06 UTC (permalink / raw)
  To: Jeremy Maitin-Shepard; +Cc: linux-kernel, linux-security-module, linux-fsdevel


--- Jeremy Maitin-Shepard <jbms@cmu.edu> wrote:

> ...
> Well, my point was exactly that App Armor doesn't (as far as I know) do
> anything to enforce the argv[0] convention,

Sounds like an opportunity for improvement then.

> nor would it in general
> prevent a confined program from making a symlink or hard link.  Even
> disregarding that, it seems very fragile in general to make an suid
> program (there would be no point in confining the execution of a
> non-suid program) perform essentially access control based on argv[0].

I think that you're being generous calling it fragile, but that's
my view, and I've seen much worse. I agree that it would be a Bad Idea,
but the fact that I think it's a bad idea is not going to prevent very
many people from trying it, and for those that do try it name based
access control might seem like just the ticket to complete their
nefarious schemes. Remember that security is a subjective thing, and
using argv[0] and AppArmor together might make some people feel better.



Casey Schaufler
casey@schaufler-ca.com

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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-05-25 17:43                   ` Casey Schaufler
  2007-05-25 18:10                     ` Jeremy Maitin-Shepard
@ 2007-05-25 20:00                     ` Andreas Gruenbacher
  2007-05-25 20:27                       ` Casey Schaufler
  1 sibling, 1 reply; 187+ messages in thread
From: Andreas Gruenbacher @ 2007-05-25 20:00 UTC (permalink / raw)
  To: casey
  Cc: Jeremy Maitin-Shepard, James Morris, linux-kernel,
	linux-security-module, linux-fsdevel

On Friday 25 May 2007 19:43, Casey Schaufler wrote:
> [...] but the AppArmor code could certainly check for that in exec by
> enforcing the argv[0] convention. It would be perfectly reasonable for a
> system that is so dependent on pathnames to require that.

Hmm ... that's a strange idea. AppArmor cannot assume anything about argv[0], 
and it would be a really bad idea to change the well-established semantics of 
argv[0].

There is no actual need for looking at argv[0], though: AppArmor decides based 
on the actual pathname of the executable...

Thanks,
Andreas

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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-05-25 20:00                     ` Andreas Gruenbacher
@ 2007-05-25 20:27                       ` Casey Schaufler
  2007-05-26  5:27                         ` Crispin Cowan
  0 siblings, 1 reply; 187+ messages in thread
From: Casey Schaufler @ 2007-05-25 20:27 UTC (permalink / raw)
  To: Andreas Gruenbacher
  Cc: Jeremy Maitin-Shepard, James Morris, linux-kernel,
	linux-security-module, linux-fsdevel


--- Andreas Gruenbacher <agruen@suse.de> wrote:

> On Friday 25 May 2007 19:43, Casey Schaufler wrote:
> > [...] but the AppArmor code could certainly check for that in exec by
> > enforcing the argv[0] convention. It would be perfectly reasonable for a
> > system that is so dependent on pathnames to require that.
> 
> Hmm ... that's a strange idea.

Yeah, I get that a lot.

> AppArmor cannot assume anything about argv[0],
> 
> and it would be a really bad idea to change the well-established semantics of
> 
> argv[0].
> 
> There is no actual need for looking at argv[0], though: AppArmor decides
> based 
> on the actual pathname of the executable...

Right. My point was that if you wanted to use the gzip/gunzip
example of a file with two names being treated differently based
on the name accessed as an argument for AppArmor you could. If
you don't want to, that's ok too. Jeremy raised a reasonable objection,
and AppArmor could address it if y'all chose to do so. I seriously
doubt that enforcing the argv[0] convention would break much, and I
also expect that if it did there's a Consultant's Retirement to be
made fixing the security hole it points out.


Casey Schaufler
casey@schaufler-ca.com

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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-05-25 19:06                       ` Casey Schaufler
@ 2007-05-26  1:40                         ` Tetsuo Handa
  2007-05-26 12:10                         ` Andreas Gruenbacher
  1 sibling, 0 replies; 187+ messages in thread
From: Tetsuo Handa @ 2007-05-26  1:40 UTC (permalink / raw)
  To: casey, jbms; +Cc: linux-kernel, linux-security-module, linux-fsdevel

Hello.

Casey Schaufler wrote:
> Sorry, but I don't understand your objection. If AppArmor is configured
> to allow everyone access to /bin/gzip but only some people access to
> /bin/gunzip and (important detail) the single binary uses argv[0]
> as documented and (another important detail) there aren't other links
> named gunzip to the binary (ok, that's lots of if's) you should be fine.

The argv[0] defines the default behavior of hard linked or symbolic linked programs,
but the behavior can be overridden using commandline options.
If you want to allow access to /bin/gzip but deny access to /bin/gunzip ,
you also need to deny access to "/bin/gzip -d" "/bin/gzip --decompress" "/bin/gzip --uncompress".
It is impossible to do so because options to override the default behavior
depends on program's design and you can't know
what programs and what options are there in the system.
Even if you know all programs and all options in the system,
it is a too tough job to find and reject options
that override the default behavior in the kernel space.

> > Well, my point was exactly that App Armor doesn't (as far as I know) do
> > anything to enforce the argv[0] convention,
> Sounds like an opportunity for improvement then.

There are (I think) three types of program invocation.

(1) Invocation of hard linked programs.

    /bin/gzip and /bin/gunzip and /bin/zcat are hard links.

    There is no problem because you can know which pathname was requested
    using d_namespace_path() with "struct linux_binprm"->file .

(2) Invocation of symbolic linked programs.

    /sbin/pidof is a symbolic link to /sbin/killall .

    There is a problem because you can't know which pathname was requested
    using d_namespace_path() with "struct linux_binprm"->file
    because the symbolic links were already derefernced inside open_exec().
    To know which pathname was requested, you need to lookup
    using "struct linux_binprm"->filename without LOOKUP_FOLLOW
    and then use d_namespace_path().
    Although there is a race condition that the pathname
    the symbolic link "struct linux_binprm"->filename points to
    may change, but it is inevitable because you can't get
    dentry and vfsmount of both "without LOOKUP_FOLLOW flag" and
    "with LOOKUP_FOLLOW flag" at the same time.

(3) Invocation of dynamically created programs with random names.

    /usr/sbin/logrotate creates files patterned /tmp/logrotate.??????
    and executes these dynamically created files.

    To keep execution of these dynamically created files under control,
    you need to aggregate pathnames of these files.
    AppArmor can't define profile if the pathname of programs is random, can it?

Usually the argv[0] and the "struct linux_binprm"->filename are the same,
but if you want to do something with argv[0], you will need to handle the (2) case
to see whether the argv[0] and "struct linux_binprm"->filename are the same.

Thanks.

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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-05-24 18:58               ` Casey Schaufler
  2007-05-25  4:14                 ` Andreas Gruenbacher
  2007-05-25  5:17                 ` Jeremy Maitin-Shepard
@ 2007-05-26  5:20                 ` Kyle Moffett
  2007-05-26 11:46                   ` Andreas Gruenbacher
                                     ` (2 more replies)
  2 siblings, 3 replies; 187+ messages in thread
From: Kyle Moffett @ 2007-05-26  5:20 UTC (permalink / raw)
  To: casey
  Cc: Andreas Gruenbacher, James Morris, linux-kernel,
	linux-security-module, linux-fsdevel

On May 24, 2007, at 14:58:41, Casey Schaufler wrote:
> On Fedora zcat, gzip and gunzip are all links to the same file.  I  
> can imagine (although it is a bit of a stretch) allowing a set of  
> users access to gunzip but not gzip (or the other way around).

That is a COMPLETE straw-man argument.  I can override your "check"  
with this absolutely trivial perl code:

exec { "/usr/bin/gunzip" } "gzip", "-9", "some/file/to.gz";

Pathname-based checks are pretty fundamentally insecure.  If you want  
to protect a "name", then you should tag the "name" with security  
attributes (IE: AppArmor).  On the other hand, if you actually want  
to protect the _data_, then tagging the _name_ is flawed; tag the  
*DATA* instead.

Cheers,
Kyle Moffett


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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-05-25 20:27                       ` Casey Schaufler
@ 2007-05-26  5:27                         ` Crispin Cowan
  2007-05-26 13:34                           ` Alan Cox
  2007-05-26 18:41                           ` James Morris
  0 siblings, 2 replies; 187+ messages in thread
From: Crispin Cowan @ 2007-05-26  5:27 UTC (permalink / raw)
  To: casey
  Cc: Andreas Gruenbacher, Jeremy Maitin-Shepard, James Morris,
	linux-kernel, linux-security-module, linux-fsdevel

Casey Schaufler wrote:
> --- Andreas Gruenbacher <agruen@suse.de> wrote:
>   
>> AppArmor cannot assume anything about argv[0],
>>
>> and it would be a really bad idea to change the well-established semantics of
>>
>> argv[0].
>>
>> There is no actual need for looking at argv[0], though: AppArmor decides
>> based 
>> on the actual pathname of the executable...
>>     
> Right. My point was that if you wanted to use the gzip/gunzip
> example of a file with two names being treated differently based
> on the name accessed as an argument for AppArmor you could.
AppArmor detects the pathname of the file exec'd at the time the parent
exec's it, and not anything inside the child involving argv[0].

As such, AA can detect whether you did exec("gzip") or exec("gunzip")
and apply the policy relevant to the program. It could apply different
policies to each of them, so whether it has access to /tmp/mumble/barf
depends on whether you called it 'gzip' or 'gunzip'. Caveat: it makes no
sense to profile either gzip or gunzip in the AppArmor model, so I won't
defend what kind of policy you would put on them.

Finally, AA doesn't care what the contents of the executable are. We
assume that it is a copy of metasploit or something, and confine it to
access only the resources that the policy says.

>  If
> you don't want to, that's ok too. Jeremy raised a reasonable objection,
> and AppArmor could address it if y'all chose to do so. I seriously
> doubt that enforcing the argv[0] convention would break much, and I
> also expect that if it did there's a Consultant's Retirement to be
> made fixing the security hole it points out.
>   
AppArmor does address it, and I hope this explains how we detect which
of multiple hard links to a file you used to access the file without
mucking about with argv[0].

Crispin

-- 
Crispin Cowan, Ph.D.               http://crispincowan.com/~crispin/
Director of Software Engineering   http://novell.com
		   Security: It's not linear


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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-05-26  5:20                 ` Kyle Moffett
@ 2007-05-26 11:46                   ` Andreas Gruenbacher
  2007-05-26 12:09                     ` Tetsuo Handa
  2007-05-26 18:45                   ` [AppArmor 01/41] " James Morris
  2007-05-27  8:34                   ` Cliffe
  2 siblings, 1 reply; 187+ messages in thread
From: Andreas Gruenbacher @ 2007-05-26 11:46 UTC (permalink / raw)
  To: Kyle Moffett
  Cc: casey, James Morris, linux-kernel, linux-security-module, linux-fsdevel

On Saturday 26 May 2007 07:20, Kyle Moffett wrote:
> On May 24, 2007, at 14:58:41, Casey Schaufler wrote:
> > On Fedora zcat, gzip and gunzip are all links to the same file.  I  
> > can imagine (although it is a bit of a stretch) allowing a set of  
> > users access to gunzip but not gzip (or the other way around).
> 
> That is a COMPLETE straw-man argument.  I can override your "check"  
> with this absolutely trivial perl code:
> 
> exec { "/usr/bin/gunzip" } "gzip", "-9", "some/file/to.gz";

The above Perl code executes /usr/bin/gunzip and sets argv[0] to "gzip", so 
this confirms that the value of argv[0] is arbitrary. Well great, we already 
knew.

> Pathname-based checks are pretty fundamentally insecure.

Please don't mix apples and pears. Some utilities change their behavior based 
on argv[0], which indeed is not secure. It doesn't have to be for those 
utilities' needs. This is different from pathname-based access control, which 
is based on the pathname of the binary actually being executed.

AppArmor does not look at argv[0] for anything, and doing so would be insane. 
So please don't jump to the wrong conclusions.

You can have application-level argv[0] checks in the binary that is hardlinked 
to /bin/gzip, /bin/gunzip, /bin/zcat. At the same time, the kernel knows 
which of these three versions it is executing, so from that point of view, 
they could be as well be separate copies, and different policy can be defined 
for each one of them. (This is ignoring the fact that for small utilities 
like gzip, profile inheritance is usually more useful than defining separate 
profiles.)

Thanks,
Andreas

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

* Re: Pass struct vfsmount to the inode_create LSM hook
  2007-05-26 11:46                   ` Andreas Gruenbacher
@ 2007-05-26 12:09                     ` Tetsuo Handa
  2007-05-26 13:41                       ` Andreas Gruenbacher
  0 siblings, 1 reply; 187+ messages in thread
From: Tetsuo Handa @ 2007-05-26 12:09 UTC (permalink / raw)
  To: agruen, mrmacman_g4
  Cc: casey, jmorris, linux-kernel, linux-security-module, linux-fsdevel

Hello.

Andreas Gruenbacher wrote:
> > exec { "/usr/bin/gunzip" } "gzip", "-9", "some/file/to.gz";
> The above Perl code executes /usr/bin/gunzip and sets argv[0] to "gzip", so 
> this confirms that the value of argv[0] is arbitrary. Well great, we already 
> knew.

> AppArmor does not look at argv[0] for anything, and doing so would be insane. 
> So please don't jump to the wrong conclusions.
I agree that argv[0] checking is different from pathname-based access control
or label-based access control, but I want to say argv[0] checking is still needed.

If you don't check argv[0], an attacker can request everything like

exec { "/bin/ls" } "/sbin/busybox", "cat", "/etc/shadow";
exec { "/bin/ls" } "/sbin/busybox", "rm", "/etc/shadow";

if /bin/ls and /bin/cat and /bin/rm are hardlinks of /sbin/busybox (e.g. embedded systems).

Therefore, TOMOYO Linux checks the combination of filename and argv[0] passed to execve().

Thanks.

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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-05-25 19:06                       ` Casey Schaufler
  2007-05-26  1:40                         ` Tetsuo Handa
@ 2007-05-26 12:10                         ` Andreas Gruenbacher
  2007-05-26 22:58                           ` Casey Schaufler
  1 sibling, 1 reply; 187+ messages in thread
From: Andreas Gruenbacher @ 2007-05-26 12:10 UTC (permalink / raw)
  To: casey
  Cc: Jeremy Maitin-Shepard, linux-kernel, linux-security-module,
	linux-fsdevel

On Friday 25 May 2007 21:06, Casey Schaufler wrote:
> --- Jeremy Maitin-Shepard <jbms@cmu.edu> wrote:
> > ...
> > Well, my point was exactly that App Armor doesn't (as far as I know) do
> > anything to enforce the argv[0] convention,
>
> Sounds like an opportunity for improvement then.

Jeez, what argv[0] convention are you both talking about? argv[0] is not 
guaranteed to have any association with the name of the executable. Feel free 
to have any discussion about argv[0] you want, but *please* keep it away from 
AppArmor, which really has nothing to do with it.

It would be nice if you could stop calling argv[0] checks ``name-based access 
control'': from the point of view of the kernel no access control is 
involved, and even application-level argv[0] based access control makes no 
sense whatsoever.

Thanks,
Andreas

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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-05-26  5:27                         ` Crispin Cowan
@ 2007-05-26 13:34                           ` Alan Cox
  2007-05-26 14:05                             ` Andreas Gruenbacher
  2007-05-26 18:41                           ` James Morris
  1 sibling, 1 reply; 187+ messages in thread
From: Alan Cox @ 2007-05-26 13:34 UTC (permalink / raw)
  To: Crispin Cowan
  Cc: casey, Andreas Gruenbacher, Jeremy Maitin-Shepard, James Morris,
	linux-kernel, linux-security-module, linux-fsdevel

> As such, AA can detect whether you did exec("gzip") or exec("gunzip")
> and apply the policy relevant to the program. It could apply different

That's not actually useful for programs which link the same binary to
multiple names because if you don't consider argv[0] as well I can run
/usr/bin/gzip passing argv[0] of "gunzip" and get one set of policies and
the other set of behaviour.

And then we have user added hardlinks of course.


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

* Re: Pass struct vfsmount to the inode_create LSM hook
  2007-05-26 12:09                     ` Tetsuo Handa
@ 2007-05-26 13:41                       ` Andreas Gruenbacher
  2007-05-26 14:44                         ` Tetsuo Handa
  0 siblings, 1 reply; 187+ messages in thread
From: Andreas Gruenbacher @ 2007-05-26 13:41 UTC (permalink / raw)
  To: Tetsuo Handa
  Cc: mrmacman_g4, casey, jmorris, linux-kernel, linux-security-module,
	linux-fsdevel

On Saturday 26 May 2007 14:09, Tetsuo Handa wrote:
> Hello.
>
> Andreas Gruenbacher wrote:
> > > exec { "/usr/bin/gunzip" } "gzip", "-9", "some/file/to.gz";
> >
> > The above Perl code executes /usr/bin/gunzip and sets argv[0] to "gzip",
> > so this confirms that the value of argv[0] is arbitrary. Well great, we
> > already knew.
> >
> > AppArmor does not look at argv[0] for anything, and doing so would be
> > insane. So please don't jump to the wrong conclusions.
>
> I agree that argv[0] checking is different from pathname-based access
> control or label-based access control, but I want to say argv[0] checking
> is still needed.
>
> If you don't check argv[0], an attacker can request everything like
>
> exec { "/bin/ls" } "/sbin/busybox", "cat", "/etc/shadow";
> exec { "/bin/ls" } "/sbin/busybox", "rm", "/etc/shadow";
>
> if /bin/ls and /bin/cat and /bin/rm are hardlinks of /sbin/busybox (e.g.
> embedded systems).
>
> Therefore, TOMOYO Linux checks the combination of filename and argv[0]
> passed to execve().

So you are indeed trying to control the value of argv[0]? Well, good luck with 
that, but it's totally insane. You are guaranteed to break some applications. 
AppArmor is not going to go down that route.

If /bin/cat and /bin/rm are binaries or hardlinks to the same busybox binary 
(rather than symlinks), different profiles could be used for each of them. 
The cat profile could have no more than read access anywhere, so this would 
prevent it from removing files. That's an effective access control mechanism.

Conspiring with busybox in the kernel and making it do the right thing (and 
just that) at the application level is not an effective security mechanism: 
the kernel would still allow busybox to do anything, and there could be bugs 
in the application, busybox's calling convention could change to allow more 
than one command per invocation (e.g., ``cat /etc/shadow ; rm /etc/shadow''), 
etc.

Andreas

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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-05-26 13:34                           ` Alan Cox
@ 2007-05-26 14:05                             ` Andreas Gruenbacher
  0 siblings, 0 replies; 187+ messages in thread
From: Andreas Gruenbacher @ 2007-05-26 14:05 UTC (permalink / raw)
  To: Alan Cox
  Cc: Crispin Cowan, casey, Jeremy Maitin-Shepard, James Morris,
	linux-kernel, linux-security-module, linux-fsdevel

On Saturday 26 May 2007 15:34, Alan Cox wrote:
> > As such, AA can detect whether you did exec("gzip") or exec("gunzip")
> > and apply the policy relevant to the program. It could apply different
>
> That's not actually useful for programs which link the same binary to
> multiple names because if you don't consider argv[0] as well I can run
> /usr/bin/gzip passing argv[0] of "gunzip" and get one set of policies and
> the other set of behaviour.

I partially agree. Taken together with the policy of the calling process, 
things suddenly start to make more sense though (even if gzip/gunzip don't 
make good examples): if only allowed to execute /usr/bin/gzip, the calling 
process can still get the gunzip behavior, but it will be bound by 
the /usr/bin/gzip policy.

Controlling the policy is what we really care about; this limits the allowed 
behavior. We cannot really control the behavior of an application anyway 
(think of bugs alone), but we can set the bounds for that behavior.

> And then we have user added hardlinks of course.

Yes, allowing confined processes to change what they are allowed to execute 
under a more permissive policy is not such a good idea.

Thanks,
Andreas

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

* Re: Pass struct vfsmount to the inode_create LSM hook
  2007-05-26 13:41                       ` Andreas Gruenbacher
@ 2007-05-26 14:44                         ` Tetsuo Handa
  2007-05-26 16:52                           ` Andreas Gruenbacher
  2007-05-26 18:16                           ` Kyle Moffett
  0 siblings, 2 replies; 187+ messages in thread
From: Tetsuo Handa @ 2007-05-26 14:44 UTC (permalink / raw)
  To: agruen
  Cc: mrmacman_g4, casey, jmorris, linux-kernel, linux-security-module,
	linux-fsdevel

Hello.

Andreas Gruenbacher wrote:
> > Therefore, TOMOYO Linux checks the combination of filename and argv[0]
> > passed to execve().
> So you are indeed trying to control the value of argv[0]? Well, good luck with 
> that, but it's totally insane. You are guaranteed to break some applications.
TOMOYO Linux ristricts argv[0] using allow_argv0 syntax.
"allow_argv0 /bin/bash -bash" to allow passing "/bin/bash" to filename and "-bash" to argv[0] .
"allow_argv0 /bin/gzip gunzip" to allow passing "/bin/gzip" to filename and "gunzip" to argv[0] .
"allow_argv0 /sbin/busybox cat" to allow passing "/sbin/busybox" to filename and "cat" to argv[0] .
No need to use allow_argv0 syntax if the basename of filename and basename of argv[0] are the same
(i.e. "allow_argv0 /bin/bash bash" is not required).
TOMOYO Linux doesn't unconditionally forbid passing different values for filename and argv[0].
TOMOYO Linux allows passing different values for filename and argv[0] only if it is allowed by allow_argv0 syntax.
Could you please explain me why this approach breaks applications?

> If /bin/cat and /bin/rm are binaries or hardlinks to the same busybox binary 
> (rather than symlinks), different profiles could be used for each of them.
It is true if all processes are kept under control (e.g. strict policy in SELinux).
If there is a process that is not kept under control (e.g. targeted policy in SELinux),
you can't protect the application.
For example, an administrator may wish to allow users run /bin/ls without applying profiles
because /bin/ls won't read/write the content of files. But a malicious user may pass
"/bin/ls" to filename and "rm" to argv[0] and "/etc/shadow" to argv[1].
A malicious user may pass "/bin/ls" to filename and "/usr/sbin/httpd" to argv[0],
resulting behave as /usr/sbin/httpd without applying profiles for /usr/sbin/httpd .

Thanks.

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

* Re: Pass struct vfsmount to the inode_create LSM hook
  2007-05-26 14:44                         ` Tetsuo Handa
@ 2007-05-26 16:52                           ` Andreas Gruenbacher
  2007-05-26 18:16                           ` Kyle Moffett
  1 sibling, 0 replies; 187+ messages in thread
From: Andreas Gruenbacher @ 2007-05-26 16:52 UTC (permalink / raw)
  To: Tetsuo Handa
  Cc: mrmacman_g4, casey, jmorris, linux-kernel, linux-security-module,
	linux-fsdevel

On Saturday 26 May 2007 16:44, Tetsuo Handa wrote:
> Hello.
>
> Andreas Gruenbacher wrote:
> > > Therefore, TOMOYO Linux checks the combination of filename and argv[0]
> > > passed to execve().
> >
> > So you are indeed trying to control the value of argv[0]? Well, good luck
> > with that, but it's totally insane. You are guaranteed to break some
> > applications.
>
> TOMOYO Linux restricts argv[0] using allow_argv0 syntax.

Alright, so it's configurable. This reduces it from being broken to being a 
truly bad idea.

> For example, an administrator may wish to allow users to run /bin/ls without
> applying profiles because /bin/ls won't read/write the content of files.

No, forget that line of reasoning. As soon as you run anything unconfined that 
isn't trusted, you have basically lost control. Relying on the fact 
that /bin/ls won't do any harm is assuming to much. Features might exist that 
allow it to be abused, new features might get added, or there may be bugs. 
Just don't do it.

Andreas

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

* Re: Pass struct vfsmount to the inode_create LSM hook
  2007-05-26 14:44                         ` Tetsuo Handa
  2007-05-26 16:52                           ` Andreas Gruenbacher
@ 2007-05-26 18:16                           ` Kyle Moffett
  1 sibling, 0 replies; 187+ messages in thread
From: Kyle Moffett @ 2007-05-26 18:16 UTC (permalink / raw)
  To: Tetsuo Handa
  Cc: agruen, casey, jmorris, linux-kernel, linux-security-module,
	linux-fsdevel

On May 26, 2007, at 10:44:46, Tetsuo Handa wrote:
> Andreas Gruenbacher wrote:
>> Tetsuo Handa wrote:
>>> Therefore, TOMOYO Linux checks the combination of filename and  
>>> argv[0] passed to execve().
>>
>> So you are indeed trying to control the value of argv[0]? Well,  
>> good luck with that, but it's totally insane. You are guaranteed  
>> to break some applications.
>
> TOMOYO Linux ristricts argv[0] using allow_argv0 syntax.   
> "allow_argv0 /bin/bash -bash" to allow passing "/bin/bash" to  
> filename and "-bash" to argv[0].  "allow_argv0 /bin/gzip gunzip" to  
> allow passing "/bin/gzip" to filename and "gunzip" to argv[0].   
> "allow_argv0 /sbin/busybox cat" to allow passing "/sbin/busybox" to  
> filename and "cat" to argv[0].  No need to use allow_argv0 syntax  
> if the basename of filename and basename of argv[0] are the same  
> (i.e. "allow_argv0 /bin/bash bash" is not required).  TOMOYO Linux  
> doesn't unconditionally forbid passing different values for  
> filename and argv[0].  TOMOYO Linux allows passing different values  
> for filename and argv[0] only if it is allowed by allow_argv0 syntax.
>
> Could you please explain me why this approach breaks applications?

One of my servers runs 3 different instances of the "kadmind"  
Kerberos daemon, one for each realm which I need to be able to modify/ 
change-passwords/etc.  In order to differentiate and stop/restart the  
appropriate daemon, I have a simple starter script which runs each  
kadmind process with a unique name derived from the realm (EG:  
"kadmind(EXAMPLE.COM)", "kadmind(OTHER.EXAMPLE.COM)").  Since this is  
a Kerberos server I use a very strict SELinux-based policy, yet my  
management tools need to be able to easily add and remove realms in a  
secure fashion.  It sounds like TOMOYO Linux would not be able to  
handle this situation at all;  I would either have to completely turn  
off that security "feature" and lose most of the functionality of  
TOMOYO Linux, or hard-code the list of realms into the policy file  
and have to completely reload policy every time I need to add/remove  
realms (big gaping security hole).

Cheers,
Kyle Moffett




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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-05-26  5:27                         ` Crispin Cowan
  2007-05-26 13:34                           ` Alan Cox
@ 2007-05-26 18:41                           ` James Morris
  1 sibling, 0 replies; 187+ messages in thread
From: James Morris @ 2007-05-26 18:41 UTC (permalink / raw)
  To: Crispin Cowan
  Cc: casey, Andreas Gruenbacher, Jeremy Maitin-Shepard, linux-kernel,
	linux-security-module, linux-fsdevel

On Fri, 25 May 2007, Crispin Cowan wrote:

> Finally, AA doesn't care what the contents of the executable are. We
> assume that it is a copy of metasploit or something, and confine it to
> access only the resources that the policy says.

As long as these resources are only files.  There is no confinement beyond 
that.


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

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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-05-26  5:20                 ` Kyle Moffett
  2007-05-26 11:46                   ` Andreas Gruenbacher
@ 2007-05-26 18:45                   ` James Morris
  2007-05-26 23:08                     ` Toshiharu Harada
  2007-05-27  8:34                   ` Cliffe
  2 siblings, 1 reply; 187+ messages in thread
From: James Morris @ 2007-05-26 18:45 UTC (permalink / raw)
  To: Kyle Moffett
  Cc: casey, Andreas Gruenbacher, linux-kernel, linux-security-module,
	linux-fsdevel

On Sat, 26 May 2007, Kyle Moffett wrote:

> AppArmor).  On the other hand, if you actually want to protect the _data_,
> then tagging the _name_ is flawed; tag the *DATA* instead.

Bingo.  

(This is how traditional Unix DAC has always functioned, and is what 
SELinux does: object labeling).


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

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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-05-26 12:10                         ` Andreas Gruenbacher
@ 2007-05-26 22:58                           ` Casey Schaufler
  2007-05-27  1:33                             ` Valdis.Kletnieks
  0 siblings, 1 reply; 187+ messages in thread
From: Casey Schaufler @ 2007-05-26 22:58 UTC (permalink / raw)
  To: Andreas Gruenbacher; +Cc: linux-kernel, linux-security-module, linux-fsdevel


--- Andreas Gruenbacher <agruen@suse.de> wrote:

> On Friday 25 May 2007 21:06, Casey Schaufler wrote:
> > --- Jeremy Maitin-Shepard <jbms@cmu.edu> wrote:
> > > ...
> > > Well, my point was exactly that App Armor doesn't (as far as I know) do
> > > anything to enforce the argv[0] convention,
> >
> > Sounds like an opportunity for improvement then.
> 
> Jeez, what argv[0] convention are you both talking about?

>From the exec(3) man page:

   "The first argument, by convention, should point to the
    file name associated with the file being executed."

since the man page calls it a convention, so do I.

> argv[0] is not guaranteed to have any association with the
> name of the executable. Feel free to have any discussion
> about argv[0] you want, but *please* keep it away from
> AppArmor, which really has nothing to do with it.

As I pointed out, if you wanted to trust the argv[0] value
(which I understand AppArmor makes no claims about) and you
wanted to use the argv[0] value to determine application
behavior (which several people claim is a Bad Idea) you could
use Name Based Access Control to provide different access
to the common binary. As I pointed out before, that's a lot
of "if's".

> It would be nice if you could stop calling argv[0] checks ``name-based access
> 
> control'': from the point of view of the kernel no access control is 
> involved, and even application-level argv[0] based access control makes no 
> sense whatsoever.
 
Fair enough, I don't believe that an argv[0] check ought to
be used as a security mechanism. I am not convinced that everyone
would agree with us.



Casey Schaufler
casey@schaufler-ca.com

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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-05-26 18:45                   ` [AppArmor 01/41] " James Morris
@ 2007-05-26 23:08                     ` Toshiharu Harada
  2007-05-27  2:10                       ` Kyle Moffett
  0 siblings, 1 reply; 187+ messages in thread
From: Toshiharu Harada @ 2007-05-26 23:08 UTC (permalink / raw)
  To: James Morris
  Cc: Kyle Moffett, casey, Andreas Gruenbacher, linux-kernel,
	linux-security-module, linux-fsdevel

2007/5/27, James Morris <jmorris@namei.org>:
> On Sat, 26 May 2007, Kyle Moffett wrote:
> > AppArmor).  On the other hand, if you actually want to protect the _data_,
> > then tagging the _name_ is flawed; tag the *DATA* instead.
>
> Bingo.
>
> (This is how traditional Unix DAC has always functioned, and is what
> SELinux does: object labeling).

Object labeling (or labeled security) looks simple and straight forward way,
but it's not.

(1) Object labeling has a assumption that labels are always properly
defined and maintained. This can not be easily achieved.
(2) Also, assigning a label is something like inventing and assigning
a *new* name (label name) to objects which can cause flaws.

 I'm not saying labeled security or SELinux is wrong.  I just wanted to
remind that  the important part is the "process" not the "result". :-)

-- 
Toshiharu Harada
haradats@gmail.com

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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-05-26 22:58                           ` Casey Schaufler
@ 2007-05-27  1:33                             ` Valdis.Kletnieks
  0 siblings, 0 replies; 187+ messages in thread
From: Valdis.Kletnieks @ 2007-05-27  1:33 UTC (permalink / raw)
  To: casey
  Cc: Andreas Gruenbacher, linux-kernel, linux-security-module, linux-fsdevel

[-- Attachment #1: Type: text/plain, Size: 646 bytes --]

On Sat, 26 May 2007 15:58:50 PDT, Casey Schaufler said:
> Fair enough, I don't believe that an argv[0] check ought to
> be used as a security mechanism. I am not convinced that everyone
> would agree with us.

Having seen my share of argv[0]-related security bugs in my years, I have to
agree that it's a security crock.  As to why some might not agree, you already
put your finger on it earlier:

On Fri, 25 May 2007 12:06:19 PDT, Casey Schaufler said:
> nefarious schemes. Remember that security is a subjective thing, and
> using argv[0] and AppArmor together might make some people feel better.

Some people would rather just feel better...


[-- Attachment #2: Type: application/pgp-signature, Size: 226 bytes --]

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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-05-26 23:08                     ` Toshiharu Harada
@ 2007-05-27  2:10                       ` Kyle Moffett
  2007-05-27  2:37                         ` Valdis.Kletnieks
  2007-05-27  7:25                         ` Toshiharu Harada
  0 siblings, 2 replies; 187+ messages in thread
From: Kyle Moffett @ 2007-05-27  2:10 UTC (permalink / raw)
  To: Toshiharu Harada
  Cc: James Morris, casey, Andreas Gruenbacher, linux-kernel,
	linux-security-module, linux-fsdevel

On May 26, 2007, at 19:08:56, Toshiharu Harada wrote:
> 2007/5/27, James Morris <jmorris@namei.org>:
>> On Sat, 26 May 2007, Kyle Moffett wrote:
>>> AppArmor).  On the other hand, if you actually want to protect  
>>> the _data_, then tagging the _name_ is flawed; tag the *DATA*  
>>> instead.
>>
>> Bingo.
>>
>> (This is how traditional Unix DAC has always functioned, and is  
>> what SELinux does: object labeling).
>
> Object labeling (or labeled security) looks simple and straight  
> forward way, but it's not.
>
> (1) Object labeling has a assumption that labels are always  
> properly defined and maintained. This can not be easily achieved.

That's a circular argument, and a fairly trivial one at that.  If you  
can't properly manage your labels, then how do you expect any  
security at all?  If you can't manage your "labels", then pathname- 
based security won't work either.  This is analogous to saying  
"Pathname-based security has an assumption that path-permissions are  
always properly defined and maintained", which is equally obvious.   
If you can't achieve the first with reasonable security, then you  
probably can't achieve the second either.  Also, if you can't manage  
correct object labeling then I'm very interested in how you are  
maintaining secure Linux systems without standard DAC.

> (2) Also, assigning a label is something like inventing and  
> assigning a *new* name (label name) to objects which can cause flaws.

I don't understand how assigning new attributes to objects "can cause  
flaws", nor what flaws those might be; could you elaborate further?   
In particular, I don't see how this is really all that more  
complicated than defining additional access control in  
apache .htaccess files.  The principle is the same:  by stacking  
multiple independent security-verification mechanisms (Classical UNIX  
DAC and Apache permissions) you can increase security, albeit at an  
increased management cost.  You might also note that ".htaccess"  
files are yet another form of successful "label-based" security; the  
security context for a directory depends on the .htaccess "label"  
file found within.  The *exact* same principles apply to SELinux: you  
add additional attributes backed by a simple and powerful state- 
machine.  The cross-checks are lower-level than those from .htaccess  
files, but the principles are the same.

Cheers,
Kyle Moffett




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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-05-27  2:10                       ` Kyle Moffett
@ 2007-05-27  2:37                         ` Valdis.Kletnieks
  2007-05-27  5:32                           ` Kyle Moffett
  2007-05-27  7:25                         ` Toshiharu Harada
  1 sibling, 1 reply; 187+ messages in thread
From: Valdis.Kletnieks @ 2007-05-27  2:37 UTC (permalink / raw)
  To: Kyle Moffett
  Cc: Toshiharu Harada, James Morris, casey, Andreas Gruenbacher,
	linux-kernel, linux-security-module, linux-fsdevel

[-- Attachment #1: Type: text/plain, Size: 1873 bytes --]

On Sat, 26 May 2007 22:10:34 EDT, Kyle Moffett said:
> On May 26, 2007, at 19:08:56, Toshiharu Harada wrote:

> > (1) Object labeling has a assumption that labels are always  
> > properly defined and maintained. This can not be easily achieved.
> 
> That's a circular argument, and a fairly trivial one at that.  If you  
> can't properly manage your labels, then how do you expect any  
> security at all? 

Unfortunately, it's not at all as simple as all that. Toshiharu is quite
correct that it isn't always easy to actually implement.  Consider how
many ad-croc usages of 'restorecon' are needed to get a Fedora SELinux box
through rc.sysinit:

% grep restorecon /etc/rc.sysinit
if [ -n "$SELINUX_STATE" -a -x /sbin/restorecon ] && LC_ALL=C fgrep -q " /dev " /proc/mounts ; then
        /sbin/restorecon  -R /dev 2>/dev/null
    REBOOTFLAG=`restorecon -v /sbin/init`
[ -n "$SELINUX_STATE" ] && restorecon /dev/pts >/dev/null 2>&1
[ -n "$SELINUX_STATE" ] && restorecon /dev/mapper /dev/mapper/control >/dev/null 2>&1
                        [ -n "$SELINUX_STATE" -a -e "$path" ] && restorecon -R "$path"
                                [ -n "$SELINUX_STATE" -a -e "$path" ] && restorecon -R "$path"
                                [ -n "$SELINUX_STATE" -a -e "$path" ] && restorecon -R "$path"
   restorecon /etc/mtab /etc/ld.so.cache /etc/blkid/blkid.tab /etc/resolv.conf >/dev/null 2>&1
[ -n "$SELINUX_STATE" ] && restorecon /tmp
[ -n "$SELINUX_STATE" ] && restorecon /tmp/.ICE-unix >/dev/null 2>&1

And that's just getting the system up to single-user.  Things like sendmail
and sshd require more restorecon handholding in their rc.init files.

Or just look at the creeping horror that is 'restorecond' (in particular,
consider that the default restorcond.conf contains the strings '~/public_html'
and '~/.mozilla/plugins/libflashplayer.so'.  Yee. Frikkin. Hah. ;)


[-- Attachment #2: Type: application/pgp-signature, Size: 226 bytes --]

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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-05-27  2:37                         ` Valdis.Kletnieks
@ 2007-05-27  5:32                           ` Kyle Moffett
  2007-05-28 20:38                             ` Pavel Machek
  0 siblings, 1 reply; 187+ messages in thread
From: Kyle Moffett @ 2007-05-27  5:32 UTC (permalink / raw)
  To: Valdis.Kletnieks
  Cc: Toshiharu Harada, James Morris, casey, Andreas Gruenbacher,
	linux-kernel, linux-security-module, linux-fsdevel

On May 26, 2007, at 22:37:02, Valdis.Kletnieks@vt.edu wrote:
> On Sat, 26 May 2007 22:10:34 EDT, Kyle Moffett said:
>> On May 26, 2007, at 19:08:56, Toshiharu Harada wrote:
>
>>> (1) Object labeling has a assumption that labels are always
>>> properly defined and maintained. This can not be easily achieved.
>>
>> That's a circular argument, and a fairly trivial one at that.  If you
>> can't properly manage your labels, then how do you expect any
>> security at all?
>
> Unfortunately, it's not at all as simple as all that. Toshiharu is  
> quite correct that it isn't always easy to actually implement.   
> Consider how many ad-croc usages of 'restorecon' are needed to get  
> a Fedora SELinux box through rc.sysinit:

While I don't think restorecon is really necessary to properly boot  
SELinux-enabled (I've got a Debian box with some heavily customized  
policy which does so just fine), I am of the opinion that adding a  
"name" parameter to the file/directory create actions would be  
useful.  For example, with such support you could actually specify a  
type-transition rule conditional on a specific name or substring:

named_type_transition sshd_t tmp_t:sock_file prefix "ssh-" ssh_sock_t;

Useful options for matching would be "prefix", "suffix", "substr 
(start,len)".  "regex" would be nice but is sorta computationally  
intensive and would be likely to cause more problems than it solves.

> /sbin/restorecon  -R /dev 2>/dev/null
> [ -n "$SELINUX_STATE" ] && restorecon /dev/mapper /dev/mapper/ 
> control >/dev/null 2>&1

These can go away if you modify your policy and  pass "-o  
fscontext=system_u:object_r:dev_t" to the mount command for the /dev  
tmpfs, changing both the filesystem and the default directory labels  
from the default "system_u:object_r:tmpfs_t".  This will work as long  
as your policy files contain appropriate transitions from the dev_t  
type.

> REBOOTFLAG=`restorecon -v /sbin/init`
> restorecon /etc/mtab /etc/ld.so.cache /etc/blkid/blkid.tab /etc/ 
> resolv.conf >/dev/null 2>&1
> [ -n "$SELINUX_STATE" ] && restorecon /tmp
> [ -n "$SELINUX_STATE" ] && restorecon /tmp/.ICE-unix >/dev/null 2>&1

I believe these are to handle rebooting from non-SELinux mode.  There  
are two solutions to this kind of problem:
(1) Failing the boot if the labels are wrong
(2) Fixing the labels (and rebooting if necessary)
It would appear that FC does the latter, although for certain high- 
security systems (such as firewalls handling classified/confidential  
data), the first option is the only acceptable one.

> [ -n "$SELINUX_STATE" ] && restorecon /dev/pts >/dev/null 2>&1

I think this can be handled with some combination of appropriate  
SELinux policy and mount options.  At least, I don't need this in the  
boot scripts on my heavily customized Debian SELinux box.

> [ -n "$SELINUX_STATE" -a -e "$path" ] && restorecon -R "$path"

I don't know what the point of this generic line is; but I certainly  
don't have anything of the sort on my test system, and it appears to  
work just fine.

> And that's just getting the system up to single-user.  Things like  
> sendmail and sshd require more restorecon handholding in their  
> rc.init files.
>
> Or just look at the creeping horror that is 'restorecond' (in  
> particular, consider that the default restorcond.conf contains the  
> strings '~/public_html' and '~/.mozilla/plugins/ 
> libflashplayer.so'.  Yee. Frikkin. Hah. ;)

Part of the reason that Fedora has a large quantity of that  
restorecon and restorecond crap is that there  is a certain amount of  
broken binary software needing executable stack/heap (such as  
flashplayer), programs without comprehensive or complete policies, or  
programs which by definition need extra support for SELinux.

For example, to really complete the SELinux model you need editors  
and tools which understand security labels the same way they  
understand UNIX permissions.  With a bit of vim scripting I can  
probably make it run external commands to read file labels before it  
reads the file itself and modify /proc/self/attr/fscreate before  
writing out the file, similar to the way it would keep track of the  
standard DAC permissions on files it modifies.

There's also the fact that corporate products have fixed release  
schedules so remaining bugs in each release tend to get papered over  
instead of fixed properly (such as the restorecon in FC init- 
scripts).  I haven't seen many problems with the SELinux model which  
aren't associated with working around buggy software or missing  
features.

Cheers,
Kyle Moffett

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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-05-27  2:10                       ` Kyle Moffett
  2007-05-27  2:37                         ` Valdis.Kletnieks
@ 2007-05-27  7:25                         ` Toshiharu Harada
  2007-05-27 13:35                           ` Kyle Moffett
  1 sibling, 1 reply; 187+ messages in thread
From: Toshiharu Harada @ 2007-05-27  7:25 UTC (permalink / raw)
  To: Kyle Moffett
  Cc: James Morris, casey, Andreas Gruenbacher, linux-kernel,
	linux-security-module, linux-fsdevel

2007/5/27, Kyle Moffett <mrmacman_g4@mac.com>:
> On May 26, 2007, at 19:08:56, Toshiharu Harada wrote:
> > 2007/5/27, James Morris <jmorris@namei.org>:
> >> On Sat, 26 May 2007, Kyle Moffett wrote:
> >>> AppArmor).  On the other hand, if you actually want to protect
> >>> the _data_, then tagging the _name_ is flawed; tag the *DATA*
> >>> instead.
> >>
> >> Bingo.
> >>
> >> (This is how traditional Unix DAC has always functioned, and is
> >> what SELinux does: object labeling).
> >
> > Object labeling (or labeled security) looks simple and straight
> > forward way, but it's not.
> >
> > (1) Object labeling has a assumption that labels are always
> > properly defined and maintained. This can not be easily achieved.
>
> That's a circular argument, and a fairly trivial one at that.

Sorry Kyle, I don't think it's a trivial one.  The opposite.

> If you can't properly manage your labels, then how do you expect any
> security at all?

Please read my message again. I didn't say, "This can never be achieved".
I said, "This can not be easily achieved".

>  If you can't manage your "labels", then pathname-
> based security won't work either.  This is analogous to saying
> "Pathname-based security has an assumption that path-permissions are
> always properly defined and maintained", which is equally obvious.

Yes,! You got the point.
Both label-based and pathname-based apporaches have the advantaes and
difficluties.
In that sense they are equal. That's what I wanted to say.
Both approaches can be improved and even can be used combined to
overcome the difficulties. Let's not fight against and think together,
then we can make Linux better.

> If you can't achieve the first with reasonable security, then you
> probably can't achieve the second either.  Also, if you can't manage
> correct object labeling then I'm very interested in how you are
> maintaining secure Linux systems without standard DAC.

I'm very interested in how you can know that you have the
correct object labeling (this is my point). Could you tell?
I assume your best efforts end up with
- have a proper fc definitions and guard them (this can be done)
- executes relabeling as needed (best efforts)
- hope everything work fine

> > (2) Also, assigning a label is something like inventing and
> > assigning a *new* name (label name) to objects which can cause flaws.
>
> I don't understand how assigning new attributes to objects "can cause
> flaws", nor what flaws those might be; could you elaborate further?
> In particular, I don't see how this is really all that more
> complicated than defining additional access control in
> apache .htaccess files.  The principle is the same:  by stacking
> multiple independent security-verification mechanisms (Classical UNIX
> DAC and Apache permissions) you can increase security, albeit at an
> increased management cost.  You might also note that ".htaccess"
> files are yet another form of successful "label-based" security; the
> security context for a directory depends on the .htaccess "label"
> file found within.  The *exact* same principles apply to SELinux: you
> add additional attributes backed by a simple and powerful state-
> machine.  The cross-checks are lower-level than those from .htaccess
> files, but the principles are the same.

I don't deny DAC at all.  If we deny DAC, we can't live with Linux
it's the base.  MAC can be used to cover the shortages of DAC and
Linux's simple user model, that's it.

>From security point of view, simplicity is always the virtue and the way to go.
Inode combined label is guaranteed to be a single at any point time.
This is the most noticeable advantage of label-based security.
But writing policy with labels are somewhat indirect way (I mean, we need
"ls -Z" or "ps -Z").  Indirect way can cause flaw so we need a lot of work
that is  what I wanted to tell.

Cheers,
Toshiharu Harada
haradats@gmail.com

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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-05-26  5:20                 ` Kyle Moffett
  2007-05-26 11:46                   ` Andreas Gruenbacher
  2007-05-26 18:45                   ` [AppArmor 01/41] " James Morris
@ 2007-05-27  8:34                   ` Cliffe
  2007-05-27 13:07                     ` Kyle Moffett
  2007-05-27 16:12                     ` Casey Schaufler
  2 siblings, 2 replies; 187+ messages in thread
From: Cliffe @ 2007-05-27  8:34 UTC (permalink / raw)
  To: Kyle Moffett
  Cc: casey, Andreas Gruenbacher, James Morris, linux-kernel,
	linux-security-module, linux-fsdevel

 >> On the other hand, if you actually want to protect the _data_, then 
tagging the _name_ is flawed; tag the *DATA* instead.

Would it make sense to label the data (resource) with a list of paths 
(names) that can be used to access it?

Therefore the data would be protected against being accessed via 
alternative arbitrary names. This may be a simple label to maintain and 
(possibly to) enforce, allowing path based confinement to protect a 
resource. This may allow for the benefits of pathname based confinement 
while avoiding some of its problems.

Obviously this would not protect against a pathname pointing to 
arbitrary data…


Just a thought.

Z. Cliffe Schreuders.



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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-05-27  8:34                   ` Cliffe
@ 2007-05-27 13:07                     ` Kyle Moffett
  2007-05-27 16:12                     ` Casey Schaufler
  1 sibling, 0 replies; 187+ messages in thread
From: Kyle Moffett @ 2007-05-27 13:07 UTC (permalink / raw)
  To: Cliffe
  Cc: Andreas Gruenbacher, LKML Kernel, linux-security-module, linux-fsdevel

CC trimmed to remove a few poor overloaded inboxes from this tangent.

On May 27, 2007, at 04:34:10, Cliffe wrote:
> Kyle wrote:
>> On the other hand, if you actually want to protect the _data_,  
>> then tagging the _name_ is flawed; tag the *DATA* instead.
>
> Would it make sense to label the data (resource) with a list of  
> paths (names) that can be used to access it?
>
> Therefore the data would be protected against being accessed via  
> alternative arbitrary names. This may be a simple label to maintain  
> and (possibly to) enforce, allowing path based confinement to  
> protect a resource. This may allow for the benefits of pathname  
> based confinement while avoiding some of its problems.

The primary problem with that is that "mv somefile otherfile" must  
change the labels, which means that every process that issues a rename 
() syscall needs to have special handling of labels.  The other  
problem is that many of the features and capabilities of SELinux get  
left by the wayside.  On an SELinux system 90% of the programs don't  
need to be modified to understand labels, since the policy can define  
automatic label transitions.  SELinux also allows you to have  
conditional label privileges based on boolean variables, something  
that cannot be done if the privileges themselves are stored in the  
filesystem.  Finally, such an approach does not allow you to  
differentiate between programs.

Cheers,
Kyle Moffett


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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-05-27  7:25                         ` Toshiharu Harada
@ 2007-05-27 13:35                           ` Kyle Moffett
  2007-05-28 10:41                             ` Toshiharu Harada
  0 siblings, 1 reply; 187+ messages in thread
From: Kyle Moffett @ 2007-05-27 13:35 UTC (permalink / raw)
  To: Toshiharu Harada
  Cc: James Morris, casey, Andreas Gruenbacher, linux-kernel,
	linux-security-module, linux-fsdevel

On May 27, 2007, at 03:25:27, Toshiharu Harada wrote:
> 2007/5/27, Kyle Moffett <mrmacman_g4@mac.com>:
>> On May 26, 2007, at 19:08:56, Toshiharu Harada wrote:
>>> 2007/5/27, James Morris <jmorris@namei.org>:
>>>> On Sat, 26 May 2007, Kyle Moffett wrote:
>>>>> AppArmor).  On the other hand, if you actually want to protect  
>>>>> the _data_, then tagging the _name_ is flawed; tag the *DATA*  
>>>>> instead.
>>>>
>>>> Bingo.
>>>>
>>>> (This is how traditional Unix DAC has always functioned, and is  
>>>> what SELinux does: object labeling).
>>>
>>> Object labeling (or labeled security) looks simple and straight  
>>> forward way, but it's not.
>>>
>>> (1) Object labeling has a assumption that labels are always  
>>> properly defined and maintained. This can not be easily achieved.
>>
>> That's a circular argument, and a fairly trivial one at that.
>
> Sorry Kyle, I don't think it's a trivial one.  The opposite.

How is that argument not trivially circular?  "Foo has an assumption  
that foo-property is always properly defined and maintained."  That  
could be said about *anything*:
   *  Unix permissions have an assumption that mode bits are always  
properly defined and maintained
   *  Apache .htaccess security has an assumtion that .htaccess files  
are always properly defined and maintained.
   *  Functional email communication has an assumption that the email  
servers are always properly defined and maintained

>> If you can't properly manage your labels, then how do you expect  
>> any security at all?
>
> Please read my message again. I didn't say, "This can never be  
> achieved".  I said, "This can not be easily achieved".

So you said "(data labels) can not be easily achieved".  My question  
for you is: How do you manage secure UNIX systems without standard  
UNIX permission bits?  Also:  If you have problems with data labels  
then what makes pathname based labels "easier"?  If there is  
something that could be done to improve SELinux and make it more  
readily configurable then it should probably be done.

>> If you can't achieve the first with reasonable security, then you  
>> probably can't achieve the second either.  Also, if you can't  
>> manage correct object labeling then I'm very interested in how you  
>> are maintaining secure Linux systems without standard DAC.
>
> I'm very interested in how you can know that you have the correct  
> object labeling (this is my point). Could you tell?

I know that I have the correct object labeling because:
   1) I rewrote/modified the default policy to be extremely strict on  
the system where I wanted the extra security and hassle.
   2) I ensured that the type transitions were in place for almost  
everything that needed to be done to administer the system.
   3) I wrote a file-contexts file and relabeled *once*
   4) I loaded the customized policy plus policy for restorecon and  
relabeled for the last time
   5) I reloaded the customized policy without restorecon privileges  
and without the ability to reload the policy again.
   6) I never reboot the system without enforcing mode.
   7) If there are unexpected errors or files have incorrect labels,  
I have to get the security auditor to log in on the affected system  
and relabel the problematic files manually (rare occurrence which  
requires excessive amounts of paperwork).

>>> (2) Also, assigning a label is something like inventing and  
>>> assigning a *new* name (label name) to objects which can cause  
>>> flaws.
>>
>> I don't understand how assigning new attributes to objects "can  
>> cause flaws", nor what flaws those might be; could you elaborate  
>> further? In particular, I don't see how this is really all that  
>> more complicated than defining additional access control in  
>> apache .htaccess files.  The principle is the same:  by stacking  
>> multiple independent security-verification mechanisms (Classical  
>> UNIX DAC and Apache permissions) you can increase security, albeit  
>> at an increased management cost.  You might also note that  
>> ".htaccess" files are yet another form of successful "label-based"  
>> security; the security context for a directory depends on  
>> the .htaccess "label" file found within.  The *exact* same  
>> principles apply to SELinux: you add additional attributes backed  
>> by a simple and powerful state-machine.  The cross-checks are  
>> lower-level than those from .htaccess files, but the principles  
>> are the same.
>
> I don't deny DAC at all.  If we deny DAC, we can't live with Linux  
> it's the base.  MAC can be used to cover the shortages of DAC and  
> Linux's simple user model, that's it.
>
> From security point of view, simplicity is always the virtue and  
> the way to go.  Inode combined label is guaranteed to be a single  
> at any point time.  This is the most noticeable advantage of label- 
> based security.

I would argue that pathname-based security breaks the "simplicity is  
the best virtue (of a security system)" paradigm, because it  
attributes multiple potentially-conflicting labels to the same piece  
of data.  It also cannot protect the secrecy of specific *data* as  
well as SELinux can.  For example:  In SELinux MLS a system could  
mark customer credit-card data as the "cust_private_info" category  
and it would be completely impossible for any program without the  
"cust_private_info" category to read that data, and even then it  
could only be written to files which also have "cust_private_info"  
set.  While a few privileged programs may have "mlsread" or  
"mlswrite" attributes allowing them to override such restrictions,  
it's a much stronger security guarantee than pathname-based security  
could ever provide.

> But writing policy with labels are somewhat indirect way (I mean,  
> we need "ls -Z" or "ps -Z").  Indirect way can cause flaw so we  
> need a lot of work that is what I wanted to tell.

I don't really use "ls -Z" or "ps -Z" when writing SELinux policy; I  
do that only when I actually think I mislabeled files.  Typically the  
SELinux-policy-development cycle is:
   1)  Modify and reload the policy
   2)  Relabel the affected files (either by hand or with some  
automated tool like restorecon)
   3)  Rerun the problem program or daemon
   4)  Examine the errors in the audit logs.  If there are no errors  
and it works then you're finished.
   5)  Go back to step 1 and fix your policy

Cheers,
Kyle Moffett


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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-05-27  8:34                   ` Cliffe
  2007-05-27 13:07                     ` Kyle Moffett
@ 2007-05-27 16:12                     ` Casey Schaufler
       [not found]                       ` <465AE46B.4090109@iinet.net.au>
  1 sibling, 1 reply; 187+ messages in thread
From: Casey Schaufler @ 2007-05-27 16:12 UTC (permalink / raw)
  To: Cliffe; +Cc: linux-kernel, linux-security-module, linux-fsdevel


--- Cliffe <cliffe@iinet.net.au> wrote:

>  >> On the other hand, if you actually want to protect the _data_, then 
> tagging the _name_ is flawed; tag the *DATA* instead.
> 
> Would it make sense to label the data (resource) with a list of paths 
> (names) that can be used to access it?

Program Access Lists (PALs) were* a feature of UNICOS. PALs could
contain not only the list of programs that could use them, but what
attributes the processes required as well. Further, you could
restrict or raise privilege based on the uid, gid, MAC label, and
privilege state of the process during exec based on the PAL. 

> Therefore the data would be protected against being accessed via 
> alternative arbitrary names. This may be a simple label to maintain and 
> (possibly to) enforce, allowing path based confinement to protect a 
> resource. This may allow for the benefits of pathname based confinement 
> while avoiding some of its problems.

Yep, but you still have the label based system issues, the classic
case being the text editor that uses "creat new", "unlink old",
"rename new to old". When the labeling scheme is more sopisticated
than "object gets label of subject" label management becomes a major
issue.

> Obviously this would not protect against a pathname pointing to 
> arbitrary data…

Protecting special data is easy. Protecting arbitrary data is the
problem.

> Just a thought.

Not a bad one, and it would be an easy and fun LSM to create.
If I were teaching a Linux kernel programming course I would
consider it for a class project.

-----
* I have used the past tense here in spite of the many
  instances of UNICOS still in operation. I don't believe
  that there is any current development on UNICOS.


Casey Schaufler
casey@schaufler-ca.com

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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-05-27 13:35                           ` Kyle Moffett
@ 2007-05-28 10:41                             ` Toshiharu Harada
  2007-05-29  1:54                               ` Kyle Moffett
  0 siblings, 1 reply; 187+ messages in thread
From: Toshiharu Harada @ 2007-05-28 10:41 UTC (permalink / raw)
  To: Kyle Moffett
  Cc: James Morris, casey, Andreas Gruenbacher, linux-kernel,
	linux-security-module, linux-fsdevel

[-- Attachment #1: Type: text/plain, Size: 4918 bytes --]

2007/5/27, Kyle Moffett <mrmacman_g4@mac.com>:
> On May 27, 2007, at 03:25:27, Toshiharu Harada wrote:
> > 2007/5/27, Kyle Moffett <mrmacman_g4@mac.com>:

> How is that argument not trivially circular?  "Foo has an assumption
> that foo-property is always properly defined and maintained."  That
> could be said about *anything*:

What I wanted to mention was the difficulties or efforts to make
assumptions real.  I never meant a circular argument, but if you
felt so I apologize sincerely.

> >> If you can't properly manage your labels, then how do you expect
> >> any security at all?
> >
> > Please read my message again. I didn't say, "This can never be
> > achieved".  I said, "This can not be easily achieved".
>
> So you said "(data labels) can not be easily achieved".  My question
> for you is: How do you manage secure UNIX systems without standard
> UNIX permission bits?  Also:  If you have problems with data labels
> then what makes pathname based labels "easier"?  If there is
> something that could be done to improve SELinux and make it more
> readily configurable then it should probably be done.

Permission bits can be checked easily with "ls" command,
but assuring the correctness of labels are not that easy.
I'll try to explain.

The correctness of the permission bit for a given file can be judged
solely by the result of "ls" command.  The correctness of the label,
on the other hand, can't be judged without understanding of whole policy
including domain transitions. (see the attached figure)
I can imagine that once one get the complete SELinux policy,
then it is able to modify and maintain it.

I don't say making a complete SELinux policy is impossible,
and actually you said you did it.  But to be frank, I don't think
you are the average level user at all. ;-)

> > I'm very interested in how you can know that you have the correct
> > object labeling (this is my point). Could you tell?
>
> I know that I have the correct object labeling because:

Do you mind if I add this?

0) I understood the default policy and perfectly understand the
every behavior of my system.

this is where the difficulties exist.

>   1) I rewrote/modified the default policy to be extremely strict on
> the system where I wanted the extra security and hassle.
>   2) I ensured that the type transitions were in place for almost
> everything that needed to be done to administer the system.
>   3) I wrote a file-contexts file and relabeled *once*
>   4) I loaded the customized policy plus policy for restorecon and
> relabeled for the last time
>   5) I reloaded the customized policy without restorecon privileges
> and without the ability to reload the policy again.
>   6) I never reboot the system without enforcing mode.
>   7) If there are unexpected errors or files have incorrect labels,
> I have to get the security auditor to log in on the affected system
> and relabel the problematic files manually (rare occurrence which
> requires excessive amounts of paperwork).

Thank you for the procedures.  It's quite helpful.

> > I don't deny DAC at all.  If we deny DAC, we can't live with Linux
> > it's the base.  MAC can be used to cover the shortages of DAC and
> > Linux's simple user model, that's it.
> >
> > From security point of view, simplicity is always the virtue and
> > the way to go.  Inode combined label is guaranteed to be a single
> > at any point time.  This is the most noticeable advantage of label-
> > based security.
>
> I would argue that pathname-based security breaks the "simplicity is
> the best virtue (of a security system)" paradigm, because it
> attributes multiple potentially-conflicting labels to the same piece

Every pathname-based security must provide the mechanism
to prevent a conflicting/malicious access, otherwise it's junk.

I have a question for you.  With current implementation of
SELinux, only one label can be assigned.  But there are cases
that one object can be used in different context, so I think
it might help if SELinux would allow objects to have
multiple labels. (I'm not talking about conflicts here)
What do you think?

> > But writing policy with labels are somewhat indirect way (I mean,
> > we need "ls -Z" or "ps -Z").  Indirect way can cause flaw so we
> > need a lot of work that is what I wanted to tell.
>
> I don't really use "ls -Z" or "ps -Z" when writing SELinux policy; I
> do that only when I actually think I mislabeled files.

I believe what you wrote, but it may not be as easy for average Linux users.

> Typically the SELinux-policy-development cycle is:
>   1)  Modify and reload the policy
>   2)  Relabel the affected files (either by hand or with some
> automated tool like restorecon)
>   3)  Rerun the problem program or daemon
>   4)  Examine the errors in the audit logs.  If there are no errors
> and it works then you're finished.
>   5)  Go back to step 1 and fix your policy

Cheers,
Toshiharu Harada

[-- Attachment #2: fig.png --]
[-- Type: image/png, Size: 15431 bytes --]

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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-05-27  5:32                           ` Kyle Moffett
@ 2007-05-28 20:38                             ` Pavel Machek
  2007-05-29  2:00                               ` Kyle Moffett
  0 siblings, 1 reply; 187+ messages in thread
From: Pavel Machek @ 2007-05-28 20:38 UTC (permalink / raw)
  To: Kyle Moffett
  Cc: Valdis.Kletnieks, Toshiharu Harada, James Morris, casey,
	Andreas Gruenbacher, linux-kernel, linux-security-module,
	linux-fsdevel

Hi!

> >>That's a circular argument, and a fairly trivial one 
> >>at that.  If you
> >>can't properly manage your labels, then how do you 
> >>expect any
> >>security at all?
> >
> >Unfortunately, it's not at all as simple as all that. 
> >Toshiharu is  quite correct that it isn't always easy 
> >to actually implement.   Consider how many ad-croc 
> >usages of 'restorecon' are needed to get  a Fedora 
> >SELinux box through rc.sysinit:
> 
> While I don't think restorecon is really necessary to 
> properly boot  SELinux-enabled (I've got a Debian box 
> with some heavily customized  policy which does so just 
> fine), I am of the opinion that adding a  "name" 
> parameter to the file/directory create actions would be  
> useful.  For example, with such support you could 
> actually specify a  type-transition rule conditional on 
> a specific name or substring:
> 
> named_type_transition sshd_t tmp_t:sock_file prefix 
> "ssh-" ssh_sock_t;
> 
> Useful options for matching would be "prefix", "suffix", 
> "substr (start,len)".  "regex" would be nice but is 
> sorta computationally  intensive and would be likely to 
> cause more problems than it solves.

Could someone implement this? AFAICT that prevents SELinux from being
superset of AppArmor... Doing this should be significantly simpler
than whole AA, and hopefully it will end up less ugly, too.
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
       [not found]                       ` <465AE46B.4090109@iinet.net.au>
@ 2007-05-28 22:29                         ` Crispin Cowan
  2007-05-29 10:46                           ` [AppArmor 01/41] Pass struct vfsmount to the inode_create LSMhook Tetsuo Handa
  2007-05-29 14:45                           ` [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook Pavel Machek
  0 siblings, 2 replies; 187+ messages in thread
From: Crispin Cowan @ 2007-05-28 22:29 UTC (permalink / raw)
  To: Cliffe; +Cc: casey, Kyle Moffett, linux-security-module, linux-kernel

Cliffe wrote:
> The following would be used in conjunction with a pathname based
> confinement to try to provide some assurances about what a path refers
> to.
>
> "/etc/shadow" is a name to a sensitive resource. There is no guarantee
> that there are not other ways to access this resource. For example a
> link "/etc/shadowlink" or a rename to "/etc/shadownewname"
>
> Pathname based security has various advantages (such as the ability to
> have more readable and centralised policies by describing resources in
> terms of their pathnames) but the above is clearly a problem (if
> confidentiality or integrity of a specific resource is important).
>
> Could we find a way to make paths a more reliable mechanism by
> labeling the file data with a simple description of names it is
> allowed to be accessed with?
>
> If we want "/etc/shadow" to be the only way to access the shadow file
> we could label the data with "/etc/shadow". Any attempts to access
> this data using a renamed file or link would be denied (attempts to
> link or rename could also be denied).
Eloquently put.

AppArmor actually does something similar to this, by mediating all of
the ways that you can make an alias to a file. These are:

    * Symbolic links: these actually don't work for making aliases with
      respect to LSM-based security systems such as AppArmor, SELinux,
      and TOMOYO Linux, because the symbolic link is resolved before the
      access request is presented to the LSM hooks. So if you create the
      symbolic link /tmp/harmless -> /etc/shadow and then the confined
      victim tries to access /tmp/harmless, what the LSM sees is an
      attempt to access /etc/shadow.
    * Hard links: AppArmor explicitly mediates permission to make a hard
      link to a file. To be able to make a hard link /tmp/harmless ->
      /etc/shadow you have to have explicit permission to do so, or the
      attempt to make the link is blocked. This mediation is kept
      relatively simple by the fact that you can only hard link to
      files, and not to directories.
    * Multiple mounts: Linux lets you mount the same file system
      multiple times at multiple mount points, so the same file could
      appear at two different places. AppArmor has very coarse mediation
      here, and simply prohibits all calls to mount() without special
      permission. So only highly privileged processes can create such an
      alias.
    * Name spaces: Linux name spaces present a similar issue, and
      AppArmor's coarse blocking of mount() serves the same function;
      only highly privileged processes are permitted to create name spaces.


> We could label a document with "/home/me/documents/*". Then the
> document could be linked or renamed within that specified directory.
We are thinking about something kind of like this for finer-grained
mediation of mount(). Currently it is all-or-nothing; we either totally
block the ability to create aliases with multiple mount points or name
spaces, or we totally trust the process with permission to do what it
likes with multiple mount point and name space aliases.

What we want is a more nuanced mediation of mount point and name space
manipulation, so that you can write a spec that says "/tmp/* can be
aliased any way you like, but /etc/shadow cannot be aliased at all" or
something like that.

However, not much work has been done on this, because at the moment the
AppArmor team is concentrating on making the code for current
functionality acceptable for upstreaming.

> Obvious problems with this solution:
> * it seems hard to determine what the label should be set to (setting
> it to "*" would be tempting and completely negate the whole thing,
> while setting it to the current filename would often be too restrictive).
This is equivalent to the question of what kind of access to grant to
the data. I don't see it as really difficult. What is harder is that the
specification has to specify what you can alias, and where it can
appear, and dealing with the two factors tends to make one's head hurt.

I am reminded of the pithy quote "Noalias must go. This is not
negotiable" -- Dennis Ritchie, referring to a proposed 'noalias' type
qualifier in ANSI C http://www.lysator.liu.se/c/dmr-on-noalias.html

Mediating permission to make aliases is complicated :(

> * when files are created these labels need to be created, and they may
> need to be changed.
.. if you use the approach of labeling the files :) In fact this
problem is general: label-based security has a hard time dealing with
new files in general, not just with respect to permission to create
aliases. The security policy for a newly created file is determined by
the label on the file, and so labeling new files is critical. SELinux
uses a variety of smart heuristics to decide the label of a new file:

    * the label of the parent directory
    * the label of the creating process
    * the domain for the creating process can do conditional things
      based on the label of the parent directory and the creating process
    * applications that link to libselinux can overtly set the label
      according to application logic

AppArmor, not using labels, doesn't have this problem. You can write an
AA profile with respect to files and directories that don't exist at all.

> * if this type of solution requires significant additional management
> (as it seems to) it is probably not a suitable addition to a pathname
> based confinement mechanism.
As I explained above, a lot of it is already in place with our mediation
of hard links. Our mediation of multiple mount points and name spaces is
lame, but the extent to which this needs to be improved will largely be
determined by how application developers choose to use these features.
Because AppArmor is intended primarily to confine applications, an
administrative approach of just using unconfined (completely trusted)
shells to manipulate name spaces and multiple mount points suffices, and
application manipulation of name spaces and multiple mount points is the
only concern.

> * A program creating a new file and copying the contents of the file
> is outside of the scope of this solution.
That is the information flow problem. While important, it is fairly
separate from the alias problem. The information flow problem is general
to all access control systems, while the alias problem is special to
name-based access control systems.

This is one of the name/label trade-offs. Aliasing is problematic in
name based systems, while new file creation is problematic in label
based systems. This follows directly from the semantics each system is
using:

    * Names are references. Name based systems are really mediating
      access to references. Thus creating new references and who can
      access these new references is problematic.
    * Labels are equivalence classes of objects. Label based systems are
      really mediating access to objects, regardless of the reference.
      Thus creating new objects and who can access these new objects is
      problematic.


> * Stoping a path from pointing to arbitrary data is also outside the
> scope of this solution (for example "/etc/shadow" could be replaced
> with another file).
This depends on where you place the "may alias" access control. You can
put it on the source (/tmp/harmless -> somewhere) on the target
(somewhere -> /etc/shadow) or somewhere else (what AppArmor does,
associating the policy with confined processes).

> Could a name based policy include the pathname as well as an inode
> number or some (more secure) identifying attribute (which could be
> calculated based on the supplied pathname)? A one-way-hash would
> identify but could not be used for each file a program accesses as
> they can change...
It could be done, but that has implications. That would mean that you
get the "belt and suspenders" effect of all of the security benefits of
(say) AppArmor and SELinux. But the non-overlapping security benefits
are relatively small (SELinux advocates may dispute this, but whatever,
it is some magnitude). On the other hand, you would get the management
problems of both AppArmor and SELinux; you would have to solve both the
new file problem, and the file alias problem. Think about what you would
have to do to accommodate (say) a text editor's file save procedure of
"write new file.tmp, rename oldfile to oldfile.old, rename newfile.tmp
to oldfile, delete oldfile.old".

So it could be done, but AFAICT, with small benefit and large cost. More
security may be more secure, but it isn't necessarily better.

Crispin

-- 
Crispin Cowan, Ph.D.               http://crispincowan.com/~crispin/
Director of Software Engineering   http://novell.com
		   Security: It's not linear


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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-05-28 10:41                             ` Toshiharu Harada
@ 2007-05-29  1:54                               ` Kyle Moffett
  2007-05-29 21:17                                 ` Valdis.Kletnieks
  2007-05-30  2:38                                 ` Toshiharu Harada
  0 siblings, 2 replies; 187+ messages in thread
From: Kyle Moffett @ 2007-05-29  1:54 UTC (permalink / raw)
  To: Toshiharu Harada
  Cc: James Morris, casey, Andreas Gruenbacher, linux-kernel,
	linux-security-module, linux-fsdevel

On May 28, 2007, at 06:41:11, Toshiharu Harada wrote:
> 2007/5/27, Kyle Moffett <mrmacman_g4@mac.com>:
>>>> If you can't properly manage your labels, then how do you expect  
>>>> any security at all?
>>> Please read my message again. I didn't say, "This can never be  
>>> achieved".  I said, "This can not be easily achieved".
>>
>> So you said "(data labels) can not be easily achieved".  My  
>> question for you is: How do you manage secure UNIX systems without  
>> standard UNIX permission bits?  Also:  If you have problems with  
>> data labels then what makes pathname based labels "easier"?  If  
>> there is something that could be done to improve SELinux and make  
>> it more readily configurable then it should probably be done.
>
> Permission bits can be checked easily with "ls" command but  
> assuring the correctness of labels are not that easy. I'll try to  
> explain.
>
> The correctness of the permission bit for a given file can be  
> judged solely by the result of "ls" command.  The correctness of  
> the label, on the other hand, can't be judged without understanding  
> of whole policy including domain transitions. (see the attached  
> figure) I can imagine that once one get the complete SELinux  
> policy, then it is able to modify and maintain it.

That's why there are a number of efforts to make modular SELinux  
policies.  A good SELinux policy provides a few core system types and  
labels which a policy developer needs to understand, as well as some  
good macros to simplify the human-editable policy files.  For  
instance, in my customized policy a daemon run by an initscript which  
reads a single config file in /etc needs this policy (Note that I use  
"_d" as a suffix for process domains instead of the usual "_t"):

initrc_daemon(foo_exec_t, foo_d)
daemon_config(foo_d, foo_conf_t)

Add maybe 2 lines for network port access, another 2 for database  
files in /var, plus maybe an "iptables" rule or two in your firewall  
file.

> I don't say making a complete SELinux policy is impossible, and  
> actually you said you did it.  But to be frank, I don't think you  
> are the average level user at all. ;-)

Average users are not supposed to be writing security policy.  To be  
honest, even average-level system administrators should not be  
writing security policy.  It's OK for such sysadmins to tweak  
existing policy to give access to additional web-docs or such, but  
only expert sysadmin/developers or security professionals should be  
writing security policy.  It's just too damn easy to get completely  
wrong.

>>> I'm very interested in how you can know that you have the correct  
>>> object labeling (this is my point). Could you tell?
>>
>> I know that I have the correct object labeling because:
>
> Do you mind if I add this?
>
> 0) I understood the default policy and perfectly understand the  
> every behavior of my system.
>
> this is where the difficulties exist.

You don't have to understand the entire default policy; that's the  
point of modular policy.  You only have to understand how to _use_  
the interfaces of the system policy (which are documented) and how  
the particular daemon policy is supposed to work.  The people  
developing the core system policy need to understand the inner  
workings of said policy, but they don't need to understand how the  
rest of the system works.  The core functionality behind this  
separation is macro interfaces and attributes.  By grouping types  
with attributes it is possible for arbitrary daemon types to  
categorize themselves under access rules defined by the base policy,  
and with interfaces the daemons don't really even need to know what  
those attributes are called.

>>> I don't deny DAC at all.  If we deny DAC, we can't live with  
>>> Linux it's the base.  MAC can be used to cover the shortages of  
>>> DAC and Linux's simple user model, that's it.
>>>
>>> From security point of view, simplicity is always the virtue and  
>>> the way to go.  Inode combined label is guaranteed to be a single  
>>> at any point time.  This is the most noticeable advantage of  
>>> label-based security.
>>
>> I would argue that pathname-based security breaks the "simplicity  
>> is the best virtue (of a security system)" paradigm, because it  
>> attributes multiple potentially-conflicting labels to the same piece
>
> I have a question for you.  With current implementation of SELinux,  
> only one label can be assigned.  But there are cases
> that one object can be used in different context, so I think it  
> might help if SELinux would allow objects to have multiple labels.  
> (I'm not talking about conflicts here)  What do you think?

This is the whole advantage of SELinux type attributes: you can  
define a type "var_foo_t" which has a specific list of attributes;  
rules which accept type specifiers can also accept attribute  
specifiers as well.  If what you want is a label which may be  
accessed in two different ways, then you declare attributes for each  
access method and declare a type which has the attributes "filetype",  
"access1", and "access2" (assuming access1 and access2 are the names  
of the attributes you declared and used in your access rules).

>>> But writing policy with labels are somewhat indirect way (I mean,  
>>> we need "ls -Z" or "ps -Z").  Indirect way can cause flaw so we  
>>> need a lot of work that is what I wanted to tell.
>>
>> I don't really use "ls -Z" or "ps -Z" when writing SELinux policy; I
>> do that only when I actually think I mislabeled files.
>
> I believe what you wrote, but it may not be as easy for average  
> Linux users.

As I said before, average Linux users should not be writing their own  
security policy.  I have yet to meet an "average Linux user" who  
could reliably quote for me what the file permissions on the "/tmp"  
directory should be, or what the sticky bit was.  A small percentage  
of average Linux system administrators don't get that right  
consistently, and if you don't understand the sticky bit then you  
should *definitely* not be controlling program permissions on a per- 
syscall basis.

Cheers,
Kyle Moffett


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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-05-28 20:38                             ` Pavel Machek
@ 2007-05-29  2:00                               ` Kyle Moffett
  0 siblings, 0 replies; 187+ messages in thread
From: Kyle Moffett @ 2007-05-29  2:00 UTC (permalink / raw)
  To: Pavel Machek
  Cc: Valdis.Kletnieks, Toshiharu Harada, James Morris, casey,
	Andreas Gruenbacher, linux-kernel, linux-security-module,
	linux-fsdevel

On May 28, 2007, at 16:38:38, Pavel Machek wrote:
> Kyle Moffett wrote:
>> I am of the opinion that adding a  "name" parameter to the file/ 
>> directory create actions would be useful.  For example, with such  
>> support you could actually specify a  type-transition rule  
>> conditional on a specific name or substring:
>>
>> named_type_transition sshd_t tmp_t:sock_file prefix "ssh-"  
>> ssh_sock_t;
>>
>> Useful options for matching would be "prefix", "suffix", "substr  
>> (start,len)".  "regex" would be nice but is sorta computationally  
>> intensive and would be likely to cause more problems than it solves.
>
> Could someone implement this? AFAICT that prevents SELinux from  
> being superset of AppArmor... Doing this should be significantly  
> simpler than whole AA, and hopefully it will end up less ugly, too.

Really it would need to extend all action-match items with new  
"named_" equivalents, and most callbacks would need to be extended to  
pass in an object name, if available.  On the other hand, with such  
support implemented then the AppArmor policy compilation tools could  
be transformed into a simple SELinux policy generator.  I estimate  
that the number of new lines of kernel code for such a modified  
SELinux would be 100x less than the kernel code in AppArmor.

Cheers,
Kyle Moffett


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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSMhook
  2007-05-28 22:29                         ` Crispin Cowan
@ 2007-05-29 10:46                           ` Tetsuo Handa
  2007-05-29 15:52                             ` Casey Schaufler
  2007-05-29 17:07                             ` Andreas Gruenbacher
  2007-05-29 14:45                           ` [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook Pavel Machek
  1 sibling, 2 replies; 187+ messages in thread
From: Tetsuo Handa @ 2007-05-29 10:46 UTC (permalink / raw)
  To: crispin, cliffe; +Cc: casey, mrmacman_g4, linux-security-module, linux-kernel

Hello.

Crispin Cowan wrote:
> AppArmor actually does something similar to this, by mediating all of
> the ways that you can make an alias to a file. These are:
> 
>     * Symbolic links: these actually don't work for making aliases with
>       respect to LSM-based security systems such as AppArmor, SELinux,
>       and TOMOYO Linux, because the symbolic link is resolved before the
>       access request is presented to the LSM hooks. So if you create the
>       symbolic link /tmp/harmless -> /etc/shadow and then the confined
>       victim tries to access /tmp/harmless, what the LSM sees is an
>       attempt to access /etc/shadow.
Yes, TOMOYO does so too.

Although TOMOYO is not using LSM, TOMOYO checks it by manually inserted hooks
that are called after resolving the symbolic links.

>     * Hard links: AppArmor explicitly mediates permission to make a hard
>       link to a file. To be able to make a hard link /tmp/harmless ->
>       /etc/shadow you have to have explicit permission to do so, or the
>       attempt to make the link is blocked. This mediation is kept
>       relatively simple by the fact that you can only hard link to
>       files, and not to directories.
Yes, TOMOYO does so too.

Conventional UNIX's access control can't restrict
which path_to_file can link with which another_path_to_file
because UNIX's access control is a label-based access control.
Therefore "ln /etc/shadow /tmp/harmless" becomes a problem
when introducing pathname-based access control.

TOMOYO checks the combination of both link source and destination,
using "allow_link path_to_link_source path_to_link_destination" syntax.
Therefore "ln /etc/shadow /tmp/harmless" is impossible as long as
"allow_link /etc/shadow /tmp/harmless" (or something like "allow_link /etc/\* /tmp/\*")
is not given. TOMOYO checks rename operation as well using
"allow_rename path_to_oldname path_to_newname" syntax.

>     * Multiple mounts: Linux lets you mount the same file system
>       multiple times at multiple mount points, so the same file could
>       appear at two different places. AppArmor has very coarse mediation
>       here, and simply prohibits all calls to mount() without special
>       permission. So only highly privileged processes can create such an
>       alias.
Yes, TOMOYO does so too.

But TOMOYO checks not only the capability to call mount() system call
but also the combination of "path_to_device" "path_to_mountpoint" and "filesystem_type"
using "allow_mount path_to_device path_to_mountpoint filesystem_type"
("allow_mount --bind path_to_bind_source path_to_bind_destionation" for bind mounts) syntax.

And, this is why this very long long thread began.
One of the reasons that TOMOYO doesn't use LSM is that
it is impossible to obtain "struct vfsmount" parameter inside some of LSM hook functions.
 From the label-based access control's point of view,
bind mount interferes nothing with label based access control
and passing "struct vfsmount" parameter looks redundant.
But, from the pathname-based access control's point of view,
bind mount interferes severely with pathname-based access control
because it is impossible to determine which pathname was requested.
Although both pathnames point to the same object,
TOMOYO focuses on the PROCEDURE FOR REACHING AN OBJECT
and being able to know the procedure is very important.
(In contrast, SELinux focuses on the ATTRIBUTE OF THE REQUESTED OBJECT, doesn't it?)

> So it could be done, but AFAICT, with small benefit and large cost. More
> security may be more secure, but it isn't necessarily better.
I don't think so.
I think the pathname-based access control and the label-based access control are
complementarity relation. TOMOYO can coexist with SELinux and AppArmor.
What is sad, it becomes impossible to coexist with SELinux and AppArmor if TOMOYO uses LSM.

Thanks.

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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-05-28 22:29                         ` Crispin Cowan
  2007-05-29 10:46                           ` [AppArmor 01/41] Pass struct vfsmount to the inode_create LSMhook Tetsuo Handa
@ 2007-05-29 14:45                           ` Pavel Machek
  2007-05-29 23:25                             ` david
  2007-05-30  5:42                             ` Crispin Cowan
  1 sibling, 2 replies; 187+ messages in thread
From: Pavel Machek @ 2007-05-29 14:45 UTC (permalink / raw)
  To: Crispin Cowan
  Cc: Cliffe, casey, Kyle Moffett, linux-security-module, linux-kernel

Hi!

> > If we want "/etc/shadow" to be the only way to access the shadow file
> > we could label the data with "/etc/shadow". Any attempts to access
> > this data using a renamed file or link would be denied (attempts to
> > link or rename could also be denied).
> Eloquently put.
> 
> AppArmor actually does something similar to this, by mediating all of
> the ways that you can make an alias to a file. These are:
...
>     * Hard links: AppArmor explicitly mediates permission to make a hard

Unfortunately, aparmor is by design limited to subset of distro
(network daemons). Unfortunately, some other programs (passwd, vi)
routinely make hardlinks. So AA mediating hardlink is not enough, as
vi will happily hardlink /etc/shadow into /etc/.vi-shadow-1234.

							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] 187+ messages in thread

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSMhook
  2007-05-29 10:46                           ` [AppArmor 01/41] Pass struct vfsmount to the inode_create LSMhook Tetsuo Handa
@ 2007-05-29 15:52                             ` Casey Schaufler
  2007-05-29 19:58                               ` James Morris
  2007-05-29 17:07                             ` Andreas Gruenbacher
  1 sibling, 1 reply; 187+ messages in thread
From: Casey Schaufler @ 2007-05-29 15:52 UTC (permalink / raw)
  To: Tetsuo Handa; +Cc: linux-security-module, linux-kernel


--- Tetsuo Handa <from-lsm@I-love.SAKURA.ne.jp> wrote:


> Conventional UNIX's access control can't restrict
> which path_to_file can link with which another_path_to_file
> because UNIX's access control is a label-based access control.

UNIX access control is attribute based, not label based. The
distinction may be hair splitting in the current context, but
could be significant later if the thread continues. 




Casey Schaufler
casey@schaufler-ca.com

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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSMhook
  2007-05-29 10:46                           ` [AppArmor 01/41] Pass struct vfsmount to the inode_create LSMhook Tetsuo Handa
  2007-05-29 15:52                             ` Casey Schaufler
@ 2007-05-29 17:07                             ` Andreas Gruenbacher
  2007-05-29 20:47                               ` Tetsuo Handa
  1 sibling, 1 reply; 187+ messages in thread
From: Andreas Gruenbacher @ 2007-05-29 17:07 UTC (permalink / raw)
  To: Tetsuo Handa
  Cc: crispin, cliffe, casey, mrmacman_g4, linux-security-module, linux-kernel

On Tuesday 29 May 2007 12:46, Tetsuo Handa wrote:
> But, from the pathname-based access control's point of view,
> bind mount interferes severely with pathname-based access control
> because it is impossible to determine which pathname was requested.

Wrong. It is very well possible to determine the path of a particular dentry 
(+ vfsmount) with bind mounts.

> Although both pathnames point to the same object, TOMOYO focuses on the
> PROCEDURE FOR REACHING AN OBJECT and being able to know the procedure is
> very important.

This doesn't make sense, either. With the following sequence of syscalls of 
processes A and B (both of them in the namespace root),

	A:				B:
	mkdir("/tmp/a")
	chdir("/tmp/a")
					rename("/tmp/a", "/tmp/b")
	creat("f")

the path being checked for the creat call must be "/tmp/b/f", even though 
process A never explicitly used "b". If that's not what TOMOYO is doing, then 
that's badly broken.

Andreas

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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSMhook
  2007-05-29 15:52                             ` Casey Schaufler
@ 2007-05-29 19:58                               ` James Morris
  0 siblings, 0 replies; 187+ messages in thread
From: James Morris @ 2007-05-29 19:58 UTC (permalink / raw)
  To: Casey Schaufler; +Cc: Tetsuo Handa, linux-security-module, linux-kernel

On Tue, 29 May 2007, Casey Schaufler wrote:

> > Conventional UNIX's access control can't restrict
> > which path_to_file can link with which another_path_to_file
> > because UNIX's access control is a label-based access control.
> 
> UNIX access control is attribute based, not label based. The
> distinction may be hair splitting in the current context, but
> could be significant later if the thread continues. 

What's important is that traditional DAC stores the security attributes 
of the object with the object.  Call them what you want, it matters not.


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

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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSMhook
  2007-05-29 17:07                             ` Andreas Gruenbacher
@ 2007-05-29 20:47                               ` Tetsuo Handa
  2007-05-29 22:10                                 ` Andreas Gruenbacher
  0 siblings, 1 reply; 187+ messages in thread
From: Tetsuo Handa @ 2007-05-29 20:47 UTC (permalink / raw)
  To: agruen
  Cc: crispin, cliffe, casey, mrmacman_g4, linux-security-module, linux-kernel

Hello.

Andreas Gruenbacher wrote:
> > But, from the pathname-based access control's point of view,
> > bind mount interferes severely with pathname-based access control
> > because it is impossible to determine which pathname was requested.
> Wrong. It is very well possible to determine the path of a particular dentry 
> (+ vfsmount) with bind mounts.
AppArmor can't determine which pathname (/tmp/public/file or /tmp/secret/file)
was requested by touch command if bound mount is used in the following way

# mkdir /tmp/public /tmp/secret
# mount -t tmpfs none /tmp/public
# mount --bind /tmp/public /tmp/secret
# touch /tmp/public/file

because security_inode_create() doesn't receive vfsmount, can it?
It is possible to determine that the requested pathname is either
/tmp/public/file or /tmp/secret/file by comparing address of vfsmount
available from current->namespace, but it is impossible to determine which one.

> the path being checked for the creat call must be "/tmp/b/f", even though 
> process A never explicitly used "b". If that's not what TOMOYO is doing, then 
> that's badly broken.
Yes, of course, TOMOYO checks "/tmp/b/f". What I meant PROCEDURE FOR REACHING is
"which directory does the process need to go through to reach the requested file
if the process's current directory is the root of the process's namespace".
And in this case, it is "/tmp/b/f".

Thanks.

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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-05-29  1:54                               ` Kyle Moffett
@ 2007-05-29 21:17                                 ` Valdis.Kletnieks
  2007-05-30  5:52                                   ` Crispin Cowan
  2007-05-30  2:38                                 ` Toshiharu Harada
  1 sibling, 1 reply; 187+ messages in thread
From: Valdis.Kletnieks @ 2007-05-29 21:17 UTC (permalink / raw)
  To: Kyle Moffett
  Cc: Toshiharu Harada, James Morris, casey, Andreas Gruenbacher,
	linux-kernel, linux-security-module, linux-fsdevel

[-- Attachment #1: Type: text/plain, Size: 1059 bytes --]

On Mon, 28 May 2007 21:54:46 EDT, Kyle Moffett said:

> Average users are not supposed to be writing security policy.  To be  
> honest, even average-level system administrators should not be  
> writing security policy.  It's OK for such sysadmins to tweak  
> existing policy to give access to additional web-docs or such, but  
> only expert sysadmin/developers or security professionals should be  
> writing security policy.  It's just too damn easy to get completely  
> wrong.

The single biggest challenge in computer security at the present time is how to
build *and deploy* servers that stay reasonably secure even when run by the
average wave-a-dead-chicken sysadmin, and desktop-class boxes that can survive
the best attempts of Joe Sixpack's "Ooh shiny" reflex, and Joe's kid's attempts
to evade the nannyware that Joe had somebody install.

(If you know how to build such things, don't bother replying.  If you have
actual field experience on getting significant percents of Joe Sixpacks to
switch, I need to buy you a beer or something.. ;)




[-- Attachment #2: Type: application/pgp-signature, Size: 226 bytes --]

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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSMhook
  2007-05-29 20:47                               ` Tetsuo Handa
@ 2007-05-29 22:10                                 ` Andreas Gruenbacher
  2007-05-30 11:38                                   ` Tetsuo Handa
  0 siblings, 1 reply; 187+ messages in thread
From: Andreas Gruenbacher @ 2007-05-29 22:10 UTC (permalink / raw)
  To: Tetsuo Handa
  Cc: crispin, cliffe, casey, mrmacman_g4, linux-security-module, linux-kernel

On Tuesday 29 May 2007 22:47, Tetsuo Handa wrote:
> AppArmor can't determine which pathname (/tmp/public/file or
> /tmp/secret/file) was requested by touch command if bound mount is used in
> the following way 
> 
> # mkdir /tmp/public /tmp/secret
> # mount -t tmpfs none /tmp/public
> # mount --bind /tmp/public /tmp/secret
> # touch /tmp/public/file
> 
> because security_inode_create() doesn't receive vfsmount, can it?

I don't know what you are talking about -- the very first patch in the 
AppArmor series adds the vfsmount parameter to security_inode_create().

Andreas

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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-05-29 14:45                           ` [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook Pavel Machek
@ 2007-05-29 23:25                             ` david
  2007-05-29 23:30                               ` Pavel Machek
  2007-05-30  5:42                             ` Crispin Cowan
  1 sibling, 1 reply; 187+ messages in thread
From: david @ 2007-05-29 23:25 UTC (permalink / raw)
  To: Pavel Machek
  Cc: Crispin Cowan, Cliffe, casey, Kyle Moffett,
	linux-security-module, linux-kernel

On Tue, 29 May 2007, Pavel Machek wrote:

> Hi!
>
>>> If we want "/etc/shadow" to be the only way to access the shadow file
>>> we could label the data with "/etc/shadow". Any attempts to access
>>> this data using a renamed file or link would be denied (attempts to
>>> link or rename could also be denied).
>> Eloquently put.
>>
>> AppArmor actually does something similar to this, by mediating all of
>> the ways that you can make an alias to a file. These are:
> ...
>>     * Hard links: AppArmor explicitly mediates permission to make a hard
>
> Unfortunately, aparmor is by design limited to subset of distro
> (network daemons). Unfortunately, some other programs (passwd, vi)
> routinely make hardlinks. So AA mediating hardlink is not enough, as
> vi will happily hardlink /etc/shadow into /etc/.vi-shadow-1234.

but with the AA design of default deny this isn't a big problem unless you 
specificly allow some network daemon to access /etc/.vi-shadow-1234

in this context passwd and vi are considered trusted processes, they are 
used _after_ you authenticate onto the box.

no, this won't help you much against local users, but there are a _lot_ of 
boxes out there with few, if any, local users who don't also have the root 
password. AA helps the admin be safer when configuring netwrok daemons.

David Lang

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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-05-29 23:25                             ` david
@ 2007-05-29 23:30                               ` Pavel Machek
  2007-05-30  1:46                                 ` David Wagner
  0 siblings, 1 reply; 187+ messages in thread
From: Pavel Machek @ 2007-05-29 23:30 UTC (permalink / raw)
  To: david
  Cc: Crispin Cowan, Cliffe, casey, Kyle Moffett,
	linux-security-module, linux-kernel

Hi!

> >>>If we want "/etc/shadow" to be the only way to access the shadow file
> >>>we could label the data with "/etc/shadow". Any attempts to access
> >>>this data using a renamed file or link would be denied (attempts to
> >>>link or rename could also be denied).
> >>Eloquently put.
> >>
> >>AppArmor actually does something similar to this, by mediating all of
> >>the ways that you can make an alias to a file. These are:
> >...
> >>    * Hard links: AppArmor explicitly mediates permission to make a hard
> >
> >Unfortunately, aparmor is by design limited to subset of distro
> >(network daemons). Unfortunately, some other programs (passwd, vi)
> >routinely make hardlinks. So AA mediating hardlink is not enough, as
> >vi will happily hardlink /etc/shadow into /etc/.vi-shadow-1234.
> 
> but with the AA design of default deny this isn't a big problem unless you 
> specificly allow some network daemon to access /etc/.vi-shadow-1234

...or unless vi decides to hardlink into /tmp or something.

> no, this won't help you much against local users, but there are a _lot_ of 
> boxes out there with few, if any, local users who don't also have the root 
> password. AA helps the admin be safer when configuring netwrok daemons.

Hmm, I guess I'd love "it is useless on multiuser boxes" to become
standard part of AA advertising.
									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] 187+ messages in thread

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-05-29 23:30                               ` Pavel Machek
@ 2007-05-30  1:46                                 ` David Wagner
  2007-05-24 14:47                                   ` Pavel Machek
  0 siblings, 1 reply; 187+ messages in thread
From: David Wagner @ 2007-05-30  1:46 UTC (permalink / raw)
  To: linux-kernel

david@lang.hm wrote:
> no, this won't help you much against local users, [...]

Pavel Machek  wrote:
>Hmm, I guess I'd love "it is useless on multiuser boxes" to become
>standard part of AA advertising.

That's not quite what david@ said.  As I understand it, AppArmor is not
focused on preventing attacks by local users against other local users;
that's not the main problem it is trying to solve.  Rather, it's primary
purpose is to deal with attacks by remote bad guys against your network
servers.  That is a laudable goal.  Anything that helps reduce the impact
of remote exploits is bound to be useful, even if doesn't do a darn
thing to stop local users from attacking each other.

This means that AppArmor could still be useful on multiuser boxes,
even if that utility is limited to defending (some) network daemons
against remote attack (or, more precisely, reducing the damage done by
a successful remote attack against a network daemon).

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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-05-29  1:54                               ` Kyle Moffett
  2007-05-29 21:17                                 ` Valdis.Kletnieks
@ 2007-05-30  2:38                                 ` Toshiharu Harada
  1 sibling, 0 replies; 187+ messages in thread
From: Toshiharu Harada @ 2007-05-30  2:38 UTC (permalink / raw)
  To: Kyle Moffett
  Cc: James Morris, casey, Andreas Gruenbacher, linux-kernel,
	linux-security-module, linux-fsdevel

2007/5/29, Kyle Moffett <mrmacman_g4@mac.com>:
> >>> But writing policy with labels are somewhat indirect way (I mean,
> >>> we need "ls -Z" or "ps -Z").  Indirect way can cause flaw so we
> >>> need a lot of work that is what I wanted to tell.
> >>
> >> I don't really use "ls -Z" or "ps -Z" when writing SELinux policy; I
> >> do that only when I actually think I mislabeled files.
> >
> > I believe what you wrote, but it may not be as easy for average
> > Linux users.
>
> As I said before, average Linux users should not be writing their own
> security policy.  I have yet to meet an "average Linux user" who
> could reliably quote for me what the file permissions on the "/tmp"
> directory should be, or what the sticky bit was.  A small percentage
> of average Linux system administrators don't get that right
> consistently, and if you don't understand the sticky bit then you
> should *definitely* not be controlling program permissions on a per-
> syscall basis.

Thank you for your detailed and thoughtful explanation.
Things are much clear now for me. Although your explanation was
quite persuasive, I still have some concerns.

Linux is now being used literately everywhere. As devices, technologies and
Linux itself is evolving so quickly, I'm afraid the way you showed was right
but could never meet the every goal perfectly. So some areas, including
embedded and special distro I guess, there must be solutions and help  for
average level administrators.

I think there are two ways to make secure systems.  One is just
you wrote: "ask it professionals" way, the other is "making practices".
You might ask "how?" My answer to the question is pahtname-based
systems such as AppAmor and TOMOYO Linux.
They can't be compared to SELinux, but they should be considered to
supplemental tools.  At least they are helpful to analyze how Linux works.
Tweeking SELinux policy is not easy but writing policies for
them is relatively easy (I'm not talking about security here).

Not everybody can be a professional administrators, but he/she can be a
professional administrator of his/her system.  I believe there must be
solutions for non professional administrators.  That's why we developed
TOMOYO Linux (http://tomoyo.sourceforge.jp/) and so was AppArmor
I guess.  You might laugh, but we are doing this because we want to
contribute to Linux and its community. :)

Thanks,
Toshiharu Harada

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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-05-29 14:45                           ` [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook Pavel Machek
  2007-05-29 23:25                             ` david
@ 2007-05-30  5:42                             ` Crispin Cowan
  1 sibling, 0 replies; 187+ messages in thread
From: Crispin Cowan @ 2007-05-30  5:42 UTC (permalink / raw)
  To: Pavel Machek
  Cc: Cliffe, casey, Kyle Moffett, linux-security-module, linux-kernel

Pavel Machek wrote:
>>     * Hard links: AppArmor explicitly mediates permission to make a hard
>>     
> Unfortunately, aparmor is by design limited to subset of distro
> (network daemons).
That is not true. AppArmor is designed to confine any application you do
not want to trust completely. This includes network daemons (Apache,
Sendmail, BIND, etc.) network clients (Firefox, Thunderbird,
GAIM/Pidgin, etc.) and any other application that mediates trust: where
data on one side of the application is higher privilege than potential
attackers on the other side of the application.

>  Unfortunately, some other programs (passwd, vi)
> routinely make hardlinks. So AA mediating hardlink is not enough, as
> vi will happily hardlink /etc/shadow into /etc/.vi-shadow-1234.
>   
I have no idea what you are talking about. I routinely profile vim on
stage in AppArmor presentations, and it presents no such problems.

Caveat: the circumstances under which you would actually want to profile
vi are rather limited, most users would not want to do that.

In another post Pavel Machek wrote:
> Hmm, I guess I'd love "it is useless on multiuser boxes" to become
> standard part of AA advertising.
That is usually around slide 7 of the standard AppArmor presentation,
right next to the remarks about how mulituser boxes are nearly extinct
dinosaurs. AppArmor gets some of its simplicity and ease of use by not
considering that vanishing use case. Even so, AppArmor does have uses on
multiuser boxes, just not the uses Pavel wishes for. Fine, use a
different tool for a different task, AppArmor has plenty of use cases.

The limitation Pavel is referring to is that AppArmor does not secure
processes that are not profiled by AppArmor. We know, this is
intentional, and contributes to AppArmor's ease of use, and does not
generate a hole if you consider every process exposed to (say) network
attack and confine it.

Crispin

-- 
Crispin Cowan, Ph.D.               http://crispincowan.com/~crispin/
Director of Software Engineering   http://novell.com
		   Security: It's not linear


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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-05-29 21:17                                 ` Valdis.Kletnieks
@ 2007-05-30  5:52                                   ` Crispin Cowan
  2007-05-24 14:40                                     ` Pavel Machek
  2007-05-30 10:06                                     ` Alan Cox
  0 siblings, 2 replies; 187+ messages in thread
From: Crispin Cowan @ 2007-05-30  5:52 UTC (permalink / raw)
  To: Valdis.Kletnieks
  Cc: Kyle Moffett, Toshiharu Harada, James Morris, casey,
	Andreas Gruenbacher, linux-kernel, linux-security-module,
	linux-fsdevel

Valdis.Kletnieks@vt.edu wrote:
> On Mon, 28 May 2007 21:54:46 EDT, Kyle Moffett said:
>   
>> Average users are not supposed to be writing security policy.  To be  
>> honest, even average-level system administrators should not be  
>> writing security policy.
That explains so much! "SELinux: you're too dumb to use it, so just keep
your hands in your pockets." :-)

AppArmor was designed to allow your average sys admin to write a
security policy. It makes different design choices than SELinux to
achieve that goal. As a result, AppArmor is an utter failure when
compared to SELinux's goals, and SELinux in turn is an utter failure
when compared to AppArmor's goals.

Which is why we have LSM: so we don't have to have this argument here,
again.

>>   It's OK for such sysadmins to tweak  
>> existing policy to give access to additional web-docs or such, but  
>> only expert sysadmin/developers or security professionals should be  
>> writing security policy.  It's just too damn easy to get completely  
>> wrong.
>>     
> The single biggest challenge in computer security at the present time is how to
> build *and deploy* servers that stay reasonably secure even when run by the
> average wave-a-dead-chicken sysadmin, and desktop-class boxes that can survive
> the best attempts of Joe Sixpack's "Ooh shiny" reflex, and Joe's kid's attempts
> to evade the nannyware that Joe had somebody install.
>   
That is a tall order. You can mostly achieve it by not giving the user
the root password, but I'm not sure you would like the result :-)

Both SELinux and AppArmor can be configured so tightly that you are not
going to get to install malware, by preventing the user from installing
software. This isn't what users want, so they invariably bypass security
and install shiny things if they own the box. SELinux and AppArmor can't
help but fail if you put them in that kind of harm's way.

Crispin

-- 
Crispin Cowan, Ph.D.               http://crispincowan.com/~crispin/
Director of Software Engineering   http://novell.com
		   Security: It's not linear


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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-05-30  5:52                                   ` Crispin Cowan
  2007-05-24 14:40                                     ` Pavel Machek
@ 2007-05-30 10:06                                     ` Alan Cox
  1 sibling, 0 replies; 187+ messages in thread
From: Alan Cox @ 2007-05-30 10:06 UTC (permalink / raw)
  To: Crispin Cowan
  Cc: Valdis.Kletnieks, Kyle Moffett, Toshiharu Harada, James Morris,
	casey, Andreas Gruenbacher, linux-kernel, linux-security-module,
	linux-fsdevel

> >> honest, even average-level system administrators should not be  
> >> writing security policy.
> That explains so much! "SELinux: you're too dumb to use it, so just keep
> your hands in your pockets." :-)

Hardly. And there are helper tools
> 
> AppArmor was designed to allow your average sys admin to write a
> security policy. 

Which is a bit like giving a small child an Uzi 9mm and inviting them to
teach themselves to shoot.

> Both SELinux and AppArmor can be configured so tightly that you are not
> going to get to install malware, by preventing the user from installing
> software. This isn't what users want, so they invariably bypass security
> and install shiny things if they own the box. SELinux and AppArmor can't
> help but fail if you put them in that kind of harm's way.

That depends who owns the admin password. That kind of thing (coupled
with 'can install approved packages' and suitable policy) works very well
in some environments where the user doesn't get the admin password - ie
much of business.

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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSMhook
  2007-05-29 22:10                                 ` Andreas Gruenbacher
@ 2007-05-30 11:38                                   ` Tetsuo Handa
  0 siblings, 0 replies; 187+ messages in thread
From: Tetsuo Handa @ 2007-05-30 11:38 UTC (permalink / raw)
  To: agruen; +Cc: linux-security-module, linux-kernel

Hello.

Andreas Gruenbacher wrote:
> I don't know what you are talking about -- the very first patch in the 
> AppArmor series adds the vfsmount parameter to security_inode_create().
I'm talking about "the current version" of AppArmor (I mean AppArmor available for
OpenSuSE 10.1/10.2, but I should call "the previous version" of AppArmor
if you call AppArmor in this series of patch "the current version") can't handle bind mounts.
I know "the next version" of AppArmor (I mean AppArmor in this series of patch)
will be able to handle bind mounts better if these vfsmount patches are adopted.

Thanks.

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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-05-24 14:47                                   ` Pavel Machek
@ 2007-06-01 17:44                                     ` Valdis.Kletnieks
  2007-06-01 18:00                                       ` david
  2007-06-02  4:30                                       ` David Wagner
  0 siblings, 2 replies; 187+ messages in thread
From: Valdis.Kletnieks @ 2007-06-01 17:44 UTC (permalink / raw)
  To: Pavel Machek; +Cc: David Wagner, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 679 bytes --]

On Thu, 24 May 2007 14:47:27 -0000, Pavel Machek said:
> Yes, if there's significantly more remote bad guys than local bad
> guys, and if remote bad guys can't just get some local user first, AA
> still has some value.

Experience over on the Windows side of the fence indicates that "remote bad
guys get some local user first" is a *MAJOR* part of the current real-world
threat model - the vast majority of successful attacks on end-user boxes these
days start off with either "Get user to (click on link|open attachment)" or
"Subvert the path to a website (either by hacking the real site or hijacking
the DNS) and deliver a drive-by fruiting when the user visits the page".



[-- Attachment #2: Type: application/pgp-signature, Size: 226 bytes --]

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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-06-01 17:44                                     ` Valdis.Kletnieks
@ 2007-06-01 18:00                                       ` david
  2007-06-04 11:07                                         ` Pavel Machek
  2007-06-02  4:30                                       ` David Wagner
  1 sibling, 1 reply; 187+ messages in thread
From: david @ 2007-06-01 18:00 UTC (permalink / raw)
  To: Valdis.Kletnieks; +Cc: Pavel Machek, David Wagner, linux-kernel

On Fri, 1 Jun 2007, Valdis.Kletnieks@vt.edu wrote:

> On Thu, 24 May 2007 14:47:27 -0000, Pavel Machek said:
>> Yes, if there's significantly more remote bad guys than local bad
>> guys, and if remote bad guys can't just get some local user first, AA
>> still has some value.
>
> Experience over on the Windows side of the fence indicates that "remote bad
> guys get some local user first" is a *MAJOR* part of the current real-world
> threat model - the vast majority of successful attacks on end-user boxes these
> days start off with either "Get user to (click on link|open attachment)" or
> "Subvert the path to a website (either by hacking the real site or hijacking
> the DNS) and deliver a drive-by fruiting when the user visits the page".

and if your local non-root user can create a hard link to /etc/shadow and 
access it they own your box anyway (they can just set the root password to 
anything they want). since I don't hear about this happening there are 
other restrictions that prevent this anyway.

everyone recognises that AA has limits, but the way people are 
emphisising these acknowledged limits is beginning to sound a bit shrill.

David Lang


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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-06-01 17:44                                     ` Valdis.Kletnieks
  2007-06-01 18:00                                       ` david
@ 2007-06-02  4:30                                       ` David Wagner
  2007-06-02  7:40                                         ` Valdis.Kletnieks
  2007-06-08 20:24                                         ` Pavel Machek
  1 sibling, 2 replies; 187+ messages in thread
From: David Wagner @ 2007-06-02  4:30 UTC (permalink / raw)
  To: linux-kernel

Valdis.Kletnieks@vt.edu writes:
>Experience over on the Windows side of the fence indicates that "remote bad
>guys get some local user first" is a *MAJOR* part of the current real-world
>threat model - the vast majority of successful attacks on end-user boxes these
>days start off with either "Get user to (click on link|open attachment)" or
>"Subvert the path to a website (either by hacking the real site or hijacking
>the DNS) and deliver a drive-by fruiting when the user visits the page".

AppArmor isn't trying to defend everyday users from getting phished or
social engineered; it is trying to protect servers from getting rooted
because of security holes in their network daemons.  I find that a
laudable goal.  Sure, it doesn't solve every security problem in the
world, but so what?  A tool that could solve that one security problem
would still be a useful thing, even if it did nothing else.

I don't find the Windows stuff too relevant here.  As I understand it,
AppArmor isn't aimed at defending Windows desktop users; it is aimed at
defending Linux servers.  A pretty different environment, I'd say.

Ultimately, there are some things AppArmor may be good at, and there
are also sure to be some things it is bloody useless for.  My hammer
isn't very good for screwing in screws, but I still find it useful.
I confess I don't understand the kvetching about AppArmor's goals.
What are you expecting, some kind of silver bullet?

A question I'd find more interesting is whether AppArmor is able to
meet its stated goals, under a reasonable threat model, and with what
degree of assurance, and at what cost.  But I don't know whether that's
relevant for the linux-kernel mailing list.

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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-06-02  4:30                                       ` David Wagner
@ 2007-06-02  7:40                                         ` Valdis.Kletnieks
  2007-06-02 14:27                                           ` david
  2007-06-08 20:24                                         ` Pavel Machek
  1 sibling, 1 reply; 187+ messages in thread
From: Valdis.Kletnieks @ 2007-06-02  7:40 UTC (permalink / raw)
  To: David Wagner; +Cc: linux-kernel

[-- Attachment #1: Type: text/plain, Size: 2363 bytes --]

On Sat, 02 Jun 2007 04:30:30 -0000, David Wagner said:
> I don't find the Windows stuff too relevant here.

I'm surprised.  The only Windows-specific thing in the whole paragraph is that
the attack described is currently wildly successful. And there *have* been
known exploitable bugs in the Linux version of Firefox. In other words, all the
pieces are in place for exactly the same thing to work on Linux.

The type of hardening that AppArmor can provide network-facing daemons is only
protecting the system against attacks that aren't even a large part of the
threat model.   Exploiting a broken PHP script? Happens all the time, and
AppArmor can't do much for it.  SQL injection? Happens all the time, and it
can't help much there either.  Systems getting pwned because the sysadmin's
laptop got hacked? Pretty common, and another thing that AppArmor won't slow
down. But yes, I *will* grant that the next time there's a buffer overflow in
Apache, AppArmor will be able to help *that*....

>                                                    As I understand it,
> AppArmor isn't aimed at defending Windows desktop users; it is aimed at
> defending Linux servers.  A pretty different environment, I'd say.

The only reason you're not seeing the same exact threat model against Linux
servers is because it's still a minority.  It's *always* been true that one of
the most productive attacks on a server has been to find a desktop that you can
attack, and then abuse a trust relationship from the desktop to the server (and
has been, ever since the server was a IBM mainframe and the desktop was an RJE
station.  Amazing how trusting OS/360 was of a card deck tossed into a remote
card reader... :)

> Ultimately, there are some things AppArmor may be good at, and there
> are also sure to be some things it is bloody useless for.  My hammer
> isn't very good for screwing in screws, but I still find it useful.

The question is whether it's a hammer, a screwdriver, or that coping saw that
you never seem to find a use for...

> I confess I don't understand the kvetching about AppArmor's goals.
> What are you expecting, some kind of silver bullet?

Exactly the opposite - I'm worried that it will be treated as a silver bullet.

And historically, we've had an amazing amount of pushback againt things that
are intrusive and only provide a partial solution.



[-- Attachment #2: Type: application/pgp-signature, Size: 226 bytes --]

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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-06-02  7:40                                         ` Valdis.Kletnieks
@ 2007-06-02 14:27                                           ` david
  2007-06-02 19:14                                             ` Valdis.Kletnieks
  0 siblings, 1 reply; 187+ messages in thread
From: david @ 2007-06-02 14:27 UTC (permalink / raw)
  To: Valdis.Kletnieks; +Cc: David Wagner, linux-kernel

On Sat, 2 Jun 2007, Valdis.Kletnieks@vt.edu wrote:

> On Sat, 02 Jun 2007 04:30:30 -0000, David Wagner said:
>> I don't find the Windows stuff too relevant here.
>
> I'm surprised.  The only Windows-specific thing in the whole paragraph is that
> the attack described is currently wildly successful. And there *have* been
> known exploitable bugs in the Linux version of Firefox. In other words, all the
> pieces are in place for exactly the same thing to work on Linux.
>
> The type of hardening that AppArmor can provide network-facing daemons is only
> protecting the system against attacks that aren't even a large part of the
> threat model.   Exploiting a broken PHP script? Happens all the time, and
> AppArmor can't do much for it.

actually, this is _exactly_ where AppArmor is the most useful. if the PHP 
script is restricted by AppArmor it won't be able to go out and touch 
things that it's not supposed to.

> SQL injection? Happens all the time, and it
> can't help much there either.  Systems getting pwned because the sysadmin's
> laptop got hacked? Pretty common, and another thing that AppArmor won't slow
> down. But yes, I *will* grant that the next time there's a buffer overflow in
> Apache, AppArmor will be able to help *that*....
>
>>                                                    As I understand it,
>> AppArmor isn't aimed at defending Windows desktop users; it is aimed at
>> defending Linux servers.  A pretty different environment, I'd say.
>
> The only reason you're not seeing the same exact threat model against Linux
> servers is because it's still a minority.  It's *always* been true that one of
> the most productive attacks on a server has been to find a desktop that you can
> attack, and then abuse a trust relationship from the desktop to the server (and
> has been, ever since the server was a IBM mainframe and the desktop was an RJE
> station.  Amazing how trusting OS/360 was of a card deck tossed into a remote
> card reader... :)

if you are targeting one specific company or one specific server then you 
are correct, however most attacks are not that targeted, they do things 
like useing google to find random servers that are running vunerable 
software and attack that (or just try the attack against random IP 
addresses in case it happens to be running the vunerable software)

David Lang

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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-06-02 14:27                                           ` david
@ 2007-06-02 19:14                                             ` Valdis.Kletnieks
  2007-06-02 19:51                                               ` david
  0 siblings, 1 reply; 187+ messages in thread
From: Valdis.Kletnieks @ 2007-06-02 19:14 UTC (permalink / raw)
  To: david; +Cc: David Wagner, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 2723 bytes --]

On Sat, 02 Jun 2007 07:27:13 PDT, david@lang.hm said:

> > The type of hardening that AppArmor can provide network-facing daemons is only
> > protecting the system against attacks that aren't even a large part of the
> > threat model.   Exploiting a broken PHP script? Happens all the time, and
> > AppArmor can't do much for it.
> 
> actually, this is _exactly_ where AppArmor is the most useful. if the PHP 
> script is restricted by AppArmor it won't be able to go out and touch 
> things that it's not supposed to.

OK. I'll bite.  AppArmor basically only mediates filename objects.

What filename do you specify to stop it when the exploited PHP script is used
bu a spammer to send mail to millions, when it was intended to send mail only
to a specific set of people?  Wait, that's a tcp connection to localhost:25.

What filename do you specifu to stop blog comment spam and other abuses of a
content management system (remember that the PHP code *does* need write access
to the files in question)?

It might be able to stop J Random SkriptKiddy from scribbling "Y0uz Ben Pwned"
all over your home page, but it doesn't do much to control lots of other abuses
of web apps.  To be fair, SELinux can't help a lot more, because the problem
often ends up being abuse of an access privilege that the program *should*
have - for example, if it's supposed to query the database, it's hard to stop it from making
an inappropriate query at the level that AppArmor and SELinux work at.

I'm not convinced that it's solving enough *actual* problems, given that we've
rejected a lot of other "helps a little in some cases" code for kernel
inclusion.

> if you are targeting one specific company or one specific server then you 
> are correct,

There's a lot of that going around.  And they're the attacks that you need to
worry about, because you're likely to end up as a headline.

>              however most attacks are not that targeted,

There's a big difference between "most attacks" and "most attacks you should
worry about".

>                                                          they do things 
> like useing google to find random servers that are running vunerable 
> software and attack that

Rmember that at a minimum, that also means that you're Goggleable as vulnerable
to attacks that AppArmor can't stop.  And yes, Googling for vulnerable software
*is* one of the primary ways that blog spammers find the vulerable blogs.

If your site is run in such a way that you you have to worry about random
attackers who use google, your site has *bigger* security issues, and thinking
that AppArmor is going to improve things is exactly the sort of smoke screen
magic bullet that we don't want putting in the kernel.

[-- Attachment #2: Type: application/pgp-signature, Size: 226 bytes --]

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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-06-02 19:14                                             ` Valdis.Kletnieks
@ 2007-06-02 19:51                                               ` david
  2007-06-03  4:52                                                 ` Valdis.Kletnieks
  0 siblings, 1 reply; 187+ messages in thread
From: david @ 2007-06-02 19:51 UTC (permalink / raw)
  To: Valdis.Kletnieks; +Cc: David Wagner, linux-kernel

On Sat, 2 Jun 2007, Valdis.Kletnieks@vt.edu wrote:

> On Sat, 02 Jun 2007 07:27:13 PDT, david@lang.hm said:
>
>>> The type of hardening that AppArmor can provide network-facing daemons is only
>>> protecting the system against attacks that aren't even a large part of the
>>> threat model.   Exploiting a broken PHP script? Happens all the time, and
>>> AppArmor can't do much for it.
>>
>> actually, this is _exactly_ where AppArmor is the most useful. if the PHP
>> script is restricted by AppArmor it won't be able to go out and touch
>> things that it's not supposed to.
>
> OK. I'll bite.  AppArmor basically only mediates filename objects.

for now, the AppArmor folks have said that the next step is to move on to 
other objects (like network connections) after the initial step is 
accepted.

> What filename do you specify to stop it when the exploited PHP script is used
> bu a spammer to send mail to millions, when it was intended to send mail only
> to a specific set of people?  Wait, that's a tcp connection to localhost:25.
>
> What filename do you specifu to stop blog comment spam and other abuses of a
> content management system (remember that the PHP code *does* need write access
> to the files in question)?

it stops the PHP script from spawning a shell that would be considered a 
'local trusted user'

if you use SELinux and give the PHP script permission to write to your 
content management system then the PHP script can corrupt that system if 
it's exploited. AppArmor is the same way

this is Security 101 (or even more basic), if you grant a program access 
to do something you can't prevent that program from doing that something.

> It might be able to stop J Random SkriptKiddy from scribbling "Y0uz Ben Pwned"
> all over your home page, but it doesn't do much to control lots of other abuses
> of web apps.  To be fair, SELinux can't help a lot more, because the problem
> often ends up being abuse of an access privilege that the program *should*
> have - for example, if it's supposed to query the database, it's hard to stop it from making
> an inappropriate query at the level that AppArmor and SELinux work at.

it's not hard, it's impossible

how can you know if the command 'foo' sent to another program on your 
system will cause that system to erase everything it has access to or 
return 'bar'? you don't and no system tool can (and no system tool should)

if you want to control what commands one program can send to another you 
need a security proxy between them. that isn't what AppArmor or SELinux 
are trying to do so don't blame them for not doing it.

> I'm not convinced that it's solving enough *actual* problems, given that we've
> rejected a lot of other "helps a little in some cases" code for kernel
> inclusion.

you seem to want a 'only let the system do what the programmer intended' 
command, and anything less isn't solving the actual problem. by that logic 
we shouldn't bother with passwords either, since they don't completely 
solve the problem

>> if you are targeting one specific company or one specific server then you
>> are correct,
>
> There's a lot of that going around.  And they're the attacks that you need to
> worry about, because you're likely to end up as a headline.
>
>>              however most attacks are not that targeted,
>
> There's a big difference between "most attacks" and "most attacks you should
> worry about".

you first want to knock off all the things in that 'most attacks' catagory 
so that you can pay close attention to the threats that are targeted 
directly at you.

>>                                                          they do things
>> like useing google to find random servers that are running vunerable
>> software and attack that
>
> Rmember that at a minimum, that also means that you're Goggleable as vulnerable
> to attacks that AppArmor can't stop.  And yes, Googling for vulnerable software
> *is* one of the primary ways that blog spammers find the vulerable blogs.
>
> If your site is run in such a way that you you have to worry about random
> attackers who use google, your site has *bigger* security issues, and thinking
> that AppArmor is going to improve things is exactly the sort of smoke screen
> magic bullet that we don't want putting in the kernel.

when the next exploit is found is network accessable server X, AppArmor 
can prevent it from doing anything to the system that server X wasn't 
already allowed to touch.

For example, this means that it probably won't be allowed to run bash and 
provide a shell to the outside attacker.

It also means that locally exploitable bugs are less likely to be able to 
be combined with remotely exploitable bugs into complete machine takeovers 
becouse the remotely exploitable server would have to have permission to 
access the locally exploitable software.

if you can't see any advantage to this then you would be happy doing a 
chmod -R 777 / on your system (becouse normal user permissions are a much 
more restricted way of limiting the same type of access)

David Lang

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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-06-02 19:51                                               ` david
@ 2007-06-03  4:52                                                 ` Valdis.Kletnieks
  0 siblings, 0 replies; 187+ messages in thread
From: Valdis.Kletnieks @ 2007-06-03  4:52 UTC (permalink / raw)
  To: david; +Cc: David Wagner, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 4201 bytes --]

On Sat, 02 Jun 2007 12:51:27 PDT, david@lang.hm said:

> this is Security 101 (or even more basic), if you grant a program access 
> to do something you can't prevent that program from doing that something.

And Security 102 is "most of the *real* trouble starts when authorized programs
access authorized things in unintended ways".

> if you want to control what commands one program can send to another you 
> need a security proxy between them. that isn't what AppArmor or SELinux 
> are trying to do so don't blame them for not doing it.

I'm not blaming them. I'm blaming the people who are trying to sell AppArmor
as doing much more than a small bandaid on the totality of the security issue.

There's *lots* of attacks.  AppArmor only addresses a very small segment of
them, and it's quite arguably not even addressing the ones you should worry
about.

> > I'm not convinced that it's solving enough *actual* problems, given that we've
> > rejected a lot of other "helps a little in some cases" code for kernel
> > inclusion.
> 
> you seem to want a 'only let the system do what the programmer intended' 
> command, and anything less isn't solving the actual problem. by that logic 
> we shouldn't bother with passwords either, since they don't completely 
> solve the problem

No, I'm saying that we've had a *lot* of partial solutions, from Grsecurity
to signed-modules, that didn't go in to the tree because they were too intrusive
for the partial security they provided.

> you first want to knock off all the things in that 'most attacks' catagory 
> so that you can pay close attention to the threats that are targeted 
> directly at you.

Quite frankly, if you've configured your system properly, and kept things
patched, and all the other things you should be doing *anyhow*, the vast
majority of "most attacks" really shouldn't be much more than "The daily
report showed another 2,395 probes for that year-old exploit".

Remember - if you're getting hit by a "background noise" random attempt,
it is almost certainly *not* a 0-day, because any attacker who's clued enough
to *have* a 0-day has enough sense to save it for when he has a targeted attack
planned.  So there's 2 possibilities:

1) It's a random attack, and it's a *known* attack and other things (patches,
IPS, and so on) should already be mitigating the attack.

2) You're a specific target, and the fact that AppArmor stopped the attack
just means that a different attack will be made.

> For example, this means that it probably won't be allowed to run bash and 
> provide a shell to the outside attacker.

No, but I can mmap an area, make it executable, and download a block of
executable code and branch to it, giving me a shell anyhow.

> It also means that locally exploitable bugs are less likely to be able to 
> be combined with remotely exploitable bugs into complete machine takeovers 
> becouse the remotely exploitable server would have to have permission to 
> access the locally exploitable software.

Right. Instead, the locally exploitable bug is combined with an exploitable
browser bug instead. :)

> if you can't see any advantage to this then you would be happy doing a 

Oddly enough, I don't see an advantage to only closing off half the avenues of
attack. If you go digging through the SELinux and LSM archives, you'll probably
find me arguing against the SELinux 'targeted' policy, for many of the same
reasons.  And the 'targeted' policy does a better containment of things than
the AppArmor model.

> chmod -R 777 / on your system (becouse normal user permissions are a much 
> more restricted way of limiting the same type of access)

Bad analogy.  You meant "chmod -R 777 /var /etc because the file permissions
on the /lib and /usr trees are enough to stop most random attacks".

Yes, normal access permissions, being DAC, *are* a very limited way of
applying MAC.  And if you go back and read the LSM archives, the decision
was made to apply permissions/ACLS DAC first, and then apply LSM MAC, mostly
for performance and least-surprise reasons.  There's absolutely no big
theoretical reason why you couldn't chmod 777 everything, if you loaded an
LSM that implemented the necessary MAC.




[-- Attachment #2: Type: application/pgp-signature, Size: 226 bytes --]

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

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-06-01 18:00                                       ` david
@ 2007-06-04 11:07                                         ` Pavel Machek
  0 siblings, 0 replies; 187+ messages in thread
From: Pavel Machek @ 2007-06-04 11:07 UTC (permalink / raw)
  To: david; +Cc: Valdis.Kletnieks, David Wagner, linux-kernel

On Fri 2007-06-01 11:00:50, david@lang.hm wrote:
> On Fri, 1 Jun 2007, Valdis.Kletnieks@vt.edu wrote:
> 
> >On Thu, 24 May 2007 14:47:27 -0000, Pavel Machek said:
> >>Yes, if there's significantly more remote bad guys than local bad
> >>guys, and if remote bad guys can't just get some local user first, AA
> >>still has some value.
> >
> >Experience over on the Windows side of the fence indicates that "remote bad
> >guys get some local user first" is a *MAJOR* part of the current real-world
> >threat model - the vast majority of successful attacks on end-user boxes 
> >these
> >days start off with either "Get user to (click on link|open attachment)" or
> >"Subvert the path to a website (either by hacking the real site or 
> >hijacking
> >the DNS) and deliver a drive-by fruiting when the user visits the page".
> 
> and if your local non-root user can create a hard link to /etc/shadow and 
> access it they own your box anyway (they can just set the root password to 
> anything they want). 

I think you need to look how unix security works:

pavel@amd:/tmp$ ln /etc/shadow .
pavel@amd:/tmp$ cat shadow
cat: shadow: Permission denied
pavel@amd:/tmp$

Yes, regular users are permitted to hardlink shadow, no, it is not a
security hole, yes, it is a problem for AA.
									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] 187+ messages in thread

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-06-02  4:30                                       ` David Wagner
  2007-06-02  7:40                                         ` Valdis.Kletnieks
@ 2007-06-08 20:24                                         ` Pavel Machek
  2007-06-08 21:54                                           ` Casey Schaufler
  1 sibling, 1 reply; 187+ messages in thread
From: Pavel Machek @ 2007-06-08 20:24 UTC (permalink / raw)
  To: David Wagner; +Cc: linux-kernel

Hi!

(Please preserve cc lists when replying on l-k).

> >Experience over on the Windows side of the fence indicates that "remote bad
> >guys get some local user first" is a *MAJOR* part of the current real-world
> >threat model - the vast majority of successful attacks on end-user boxes these
> >days start off with either "Get user to (click on link|open attachment)" or
> >"Subvert the path to a website (either by hacking the real site or hijacking
> >the DNS) and deliver a drive-by fruiting when the user visits the page".
> 
> AppArmor isn't trying to defend everyday users from getting phished or
> social engineered; it is trying to protect servers from getting rooted
> because of security holes in their network daemons.  I find that a
> laudable goal.  Sure, it doesn't solve every security problem in the
> world, but so what?  A tool that could solve that one security problem

AA solves less problems than SELinux does. Some people like AA more,
but I guess they should just learn SELinux.

And yes, I'm afraid this discussion is relevant on l-k, because we
should have very good reasons before merging duplicate functionality.

							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] 187+ messages in thread

* Re: [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook
  2007-06-08 20:24                                         ` Pavel Machek
@ 2007-06-08 21:54                                           ` Casey Schaufler
  0 siblings, 0 replies; 187+ messages in thread
From: Casey Schaufler @ 2007-06-08 21:54 UTC (permalink / raw)
  To: Pavel Machek, David Wagner; +Cc: linux-kernel


--- Pavel Machek <pavel@ucw.cz> wrote:


> AA solves less problems than SELinux does.

And vi solves less problems than OpenOffice.
vi is good for a different set of purposes than OpenOffice.
AA and SELinux both aspire to being Security Solutions,
but that does not make either a subset of the other.

> Some people like AA more,
> but I guess they should just learn SELinux.

Knowing the people involved I would suggest that the AA people
did learn SELinux, and came to their own conclusions regarding
it's applicability to their needs, and that those conclusions
are not the same as yours.
 
> And yes, I'm afraid this discussion is relevant on l-k, because we
> should have very good reasons before merging duplicate functionality.

'cmon, you know better than to claim that this is duplicate
functionality. No one is arguing that. The arguments have been
that the conceptual basis of named based access control are flawwed.
As that argument has failed to move the AA adherants, the old sawhorse
that SELinux does everything, or could be made to if you sweated the
policy hard enough, got pulled out. No evidence to that effect,
mind you, but the old "waves paw" nonetheless.

SELinux is the finest implementation of Type Enforcement on the planet.
TE does not match everyone's definition of security. AA is an
alternative that clearly has as tough a roe to hoe as SELinux did
in 2001, when it was up against MLS system vendors who compared it
to Froot Loops. Alternatives, even those that you don't personally
care for, are good for you.



Casey Schaufler
casey@schaufler-ca.com

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

end of thread, other threads:[~2007-06-08 21:54 UTC | newest]

Thread overview: 187+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-04-12  9:08 [AppArmor 00/41] AppArmor security module overview jjohansen
2007-04-12  9:08 ` [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook jjohansen
2007-04-12 10:06   ` Christoph Hellwig
2007-04-16 16:11     ` [nameidata 1/2] Don't pass NULL nameidata to vfs_create Andreas Gruenbacher
2007-04-16 16:21       ` Christoph Hellwig
2007-04-16 16:40         ` Andreas Gruenbacher
2007-04-16 16:45           ` Christoph Hellwig
2007-04-17 12:09             ` Andreas Gruenbacher
2007-05-11 15:59         ` Andreas Gruenbacher
2007-04-16 16:25       ` Matthew Wilcox
2007-04-16 16:29     ` [nameidata 2/2] Pass no useless nameidata to the create, lookup, and permission IOPs Andreas Gruenbacher
2007-04-16 16:39       ` Christoph Hellwig
2007-04-16 16:42       ` Randy Dunlap
2007-04-16 16:44         ` Andreas Gruenbacher
2007-04-16 16:50           ` Randy Dunlap
2007-04-12 10:12   ` [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook Al Viro
2007-05-23 19:06     ` Andreas Gruenbacher
2007-05-24  1:28       ` James Morris
2007-05-24  9:16         ` Andreas Gruenbacher
2007-05-24 12:51         ` [AppArmor 01/41] Pass struct vfsmount to the inode_create LSMhook Tetsuo Handa
     [not found]         ` <200705241112.41101.agruen@suse.de>
2007-05-24 13:19           ` [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook James Morris
2007-05-24 18:10             ` Andreas Gruenbacher
2007-05-24 18:40               ` Al Viro
2007-05-24 21:56                 ` Andreas Gruenbacher
2007-05-24 18:58               ` Casey Schaufler
2007-05-25  4:14                 ` Andreas Gruenbacher
2007-05-25  5:17                 ` Jeremy Maitin-Shepard
2007-05-25 17:43                   ` Casey Schaufler
2007-05-25 18:10                     ` Jeremy Maitin-Shepard
2007-05-25 18:13                       ` Jeremy Maitin-Shepard
2007-05-25 19:06                       ` Casey Schaufler
2007-05-26  1:40                         ` Tetsuo Handa
2007-05-26 12:10                         ` Andreas Gruenbacher
2007-05-26 22:58                           ` Casey Schaufler
2007-05-27  1:33                             ` Valdis.Kletnieks
2007-05-25 20:00                     ` Andreas Gruenbacher
2007-05-25 20:27                       ` Casey Schaufler
2007-05-26  5:27                         ` Crispin Cowan
2007-05-26 13:34                           ` Alan Cox
2007-05-26 14:05                             ` Andreas Gruenbacher
2007-05-26 18:41                           ` James Morris
2007-05-26  5:20                 ` Kyle Moffett
2007-05-26 11:46                   ` Andreas Gruenbacher
2007-05-26 12:09                     ` Tetsuo Handa
2007-05-26 13:41                       ` Andreas Gruenbacher
2007-05-26 14:44                         ` Tetsuo Handa
2007-05-26 16:52                           ` Andreas Gruenbacher
2007-05-26 18:16                           ` Kyle Moffett
2007-05-26 18:45                   ` [AppArmor 01/41] " James Morris
2007-05-26 23:08                     ` Toshiharu Harada
2007-05-27  2:10                       ` Kyle Moffett
2007-05-27  2:37                         ` Valdis.Kletnieks
2007-05-27  5:32                           ` Kyle Moffett
2007-05-28 20:38                             ` Pavel Machek
2007-05-29  2:00                               ` Kyle Moffett
2007-05-27  7:25                         ` Toshiharu Harada
2007-05-27 13:35                           ` Kyle Moffett
2007-05-28 10:41                             ` Toshiharu Harada
2007-05-29  1:54                               ` Kyle Moffett
2007-05-29 21:17                                 ` Valdis.Kletnieks
2007-05-30  5:52                                   ` Crispin Cowan
2007-05-24 14:40                                     ` Pavel Machek
2007-05-30 10:06                                     ` Alan Cox
2007-05-30  2:38                                 ` Toshiharu Harada
2007-05-27  8:34                   ` Cliffe
2007-05-27 13:07                     ` Kyle Moffett
2007-05-27 16:12                     ` Casey Schaufler
     [not found]                       ` <465AE46B.4090109@iinet.net.au>
2007-05-28 22:29                         ` Crispin Cowan
2007-05-29 10:46                           ` [AppArmor 01/41] Pass struct vfsmount to the inode_create LSMhook Tetsuo Handa
2007-05-29 15:52                             ` Casey Schaufler
2007-05-29 19:58                               ` James Morris
2007-05-29 17:07                             ` Andreas Gruenbacher
2007-05-29 20:47                               ` Tetsuo Handa
2007-05-29 22:10                                 ` Andreas Gruenbacher
2007-05-30 11:38                                   ` Tetsuo Handa
2007-05-29 14:45                           ` [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook Pavel Machek
2007-05-29 23:25                             ` david
2007-05-29 23:30                               ` Pavel Machek
2007-05-30  1:46                                 ` David Wagner
2007-05-24 14:47                                   ` Pavel Machek
2007-06-01 17:44                                     ` Valdis.Kletnieks
2007-06-01 18:00                                       ` david
2007-06-04 11:07                                         ` Pavel Machek
2007-06-02  4:30                                       ` David Wagner
2007-06-02  7:40                                         ` Valdis.Kletnieks
2007-06-02 14:27                                           ` david
2007-06-02 19:14                                             ` Valdis.Kletnieks
2007-06-02 19:51                                               ` david
2007-06-03  4:52                                                 ` Valdis.Kletnieks
2007-06-08 20:24                                         ` Pavel Machek
2007-06-08 21:54                                           ` Casey Schaufler
2007-05-30  5:42                             ` Crispin Cowan
2007-05-25  8:01             ` Toshiharu Harada
2007-04-12  9:08 ` [AppArmor 02/41] Remove redundant check from proc_setattr() jjohansen
2007-04-12  9:08 ` [AppArmor 03/41] Remove redundant check from proc_sys_setattr() jjohansen
2007-04-12 10:10   ` Alan Cox
2007-04-12  9:08 ` [AppArmor 04/41] Pass struct file down to remove_suid and children jjohansen
2007-04-12  9:08 ` [AppArmor 05/41] Add a vfsmount parameter to notify_change() jjohansen
2007-04-12  9:08 ` [AppArmor 06/41] Pass struct vfsmount to the inode_setattr LSM hook jjohansen
2007-04-12  9:08 ` [AppArmor 07/41] Add struct vfsmount parameter to vfs_mkdir() jjohansen
2007-04-12  9:08 ` [AppArmor 08/41] Pass struct vfsmount to the inode_mkdir LSM hook jjohansen
2007-04-12  9:08 ` [AppArmor 09/41] Add a struct vfsmount parameter to vfs_mknod() jjohansen
2007-04-12  9:08 ` [AppArmor 10/41] Pass struct vfsmount to the inode_mknod LSM hook jjohansen
2007-04-12  9:08 ` [AppArmor 11/41] Add a struct vfsmount parameter to vfs_symlink() jjohansen
2007-04-12  9:08 ` [AppArmor 12/41] Pass struct vfsmount to the inode_symlink LSM hook jjohansen
2007-04-12  9:08 ` [AppArmor 13/41] Pass struct vfsmount to the inode_readlink " jjohansen
2007-04-12  9:08 ` [AppArmor 14/41] Add struct vfsmount parameters to vfs_link() jjohansen
2007-04-12  9:08 ` [AppArmor 15/41] Pass the struct vfsmounts to the inode_link LSM hook jjohansen
2007-04-12  9:08 ` [AppArmor 16/41] Add a struct vfsmount parameter to vfs_rmdir() jjohansen
2007-04-12  9:08 ` [AppArmor 17/41] Pass struct vfsmount to the inode_rmdir LSM hook jjohansen
2007-04-12  9:08 ` [AppArmor 18/41] call lsm hook before unhashing dentry in vfs_rmdir() jjohansen
2007-04-12  9:08 ` [AppArmor 19/41] Add a struct vfsmount parameter to vfs_unlink() jjohansen
2007-04-12  9:08 ` [AppArmor 20/41] Pass struct vfsmount to the inode_unlink LSM hook jjohansen
2007-04-12  9:08 ` [AppArmor 21/41] Add struct vfsmount parameters to vfs_rename() jjohansen
2007-04-12  9:08 ` [AppArmor 22/41] Pass struct vfsmount to the inode_rename LSM hook jjohansen
2007-04-12  9:08 ` [AppArmor 23/41] Add a struct vfsmount parameter to vfs_setxattr() jjohansen
2007-04-12  9:08 ` [AppArmor 24/41] Pass struct vfsmount to the inode_setxattr LSM hook jjohansen
2007-04-12  9:08 ` [AppArmor 25/41] Add a struct vfsmount parameter to vfs_getxattr() jjohansen
2007-04-12  9:08 ` [AppArmor 26/41] Pass struct vfsmount to the inode_getxattr LSM hook jjohansen
2007-04-12  9:08 ` [AppArmor 27/41] Add a struct vfsmount parameter to vfs_listxattr() jjohansen
2007-04-12  9:08 ` [AppArmor 28/41] Pass struct vfsmount to the inode_listxattr LSM hook jjohansen
2007-04-12  9:08 ` [AppArmor 29/41] Add a struct vfsmount parameter to vfs_removexattr() jjohansen
2007-04-12  9:08 ` [AppArmor 30/41] Pass struct vfsmount to the inode_removexattr LSM hook jjohansen
2007-04-12  9:08 ` [AppArmor 31/41] Fix __d_path() for lazy unmounts and make it unambiguous; exclude unreachable mount points from /proc/mounts jjohansen
2007-04-12  9:58   ` Alan Cox
2007-04-15 17:40     ` Andreas Gruenbacher
2007-04-16 21:57       ` Alan Cox
2007-04-17  1:35         ` Andreas Gruenbacher
2007-04-17 17:21           ` Alan Cox
2007-04-19 23:23             ` [d_path 0/7] Fixes to d_path: Respin Andreas Gruenbacher
2007-04-19 23:23               ` [d_path 1/7] Fix __d_path() for lazy unmounts and make it unambiguous Andreas Gruenbacher
2007-04-20  9:32                 ` Alan Cox
2007-04-19 23:23               ` [d_path 2/7] Make d_path() consistent across mount operations Andreas Gruenbacher
2007-04-19 23:23               ` [d_path 3/7] Add d_namespace_path() to compute namespace relative pathnames Andreas Gruenbacher
2007-04-21 12:57                 ` Tetsuo Handa
2007-04-21 16:16                   ` Andreas Gruenbacher
2007-04-19 23:23               ` [d_path 4/7] Make getcwd() only return valid paths Andreas Gruenbacher
2007-04-19 23:23               ` [d_path 5/7] Remove duplicate proc code Andreas Gruenbacher
2007-04-19 23:23               ` [d_path 6/7] Filter out disconnected paths from /proc/mounts Andreas Gruenbacher
2007-04-20  9:34                 ` Alan Cox
2007-04-19 23:23               ` [d_path 7/7] Distinguish between connected and disconnected paths in d_path() Andreas Gruenbacher
2007-04-20  9:30               ` [d_path 0/7] Fixes to d_path: Respin Alan Cox
2007-04-20 11:45                 ` Andreas Gruenbacher
2007-04-20 15:15                   ` Ulrich Drepper
2007-04-20 15:21                     ` Andreas Gruenbacher
2007-04-20 15:24                       ` Ulrich Drepper
2007-04-20 16:40                         ` Andreas Gruenbacher
2007-04-20 19:17                           ` Ulrich Drepper
2007-04-20 20:44                             ` Miklos Szeredi
2007-04-21 19:04                             ` Andreas Gruenbacher
2007-04-21 19:46                               ` Ulrich Drepper
2007-04-22  9:10                               ` Christoph Hellwig
2007-04-22 15:48                                 ` Andreas Gruenbacher
2007-04-17  6:30         ` [AppArmor 31/41] Fix __d_path() for lazy unmounts and make it unambiguous; exclude unreachable mount points from /proc/mounts Rob Meijer
2007-04-12  9:08 ` [AppArmor 32/41] Make d_path() consistent across mount operations jjohansen
2007-04-12  9:08 ` [AppArmor 33/41] Add d_namespace_path() to obtain namespace relative pathnames jjohansen
2007-04-12 10:49   ` Al Viro
2007-04-12  9:08 ` [AppArmor 34/41] Enable LSM hooks to distinguish operations on file descriptors from operations on pathnames jjohansen
2007-04-12  9:08 ` [AppArmor 35/41] Pass struct file down the inode_*xattr security LSM hooks jjohansen
2007-04-12  9:08 ` [AppArmor 36/41] Export audit subsystem for use by modules jjohansen
2007-04-12  9:08 ` [AppArmor 37/41] AppArmor: Main Part jjohansen
2007-04-12 10:37   ` Alan Cox
2007-04-13  8:17     ` Andreas Gruenbacher
2007-04-13  8:48     ` Andreas Gruenbacher
2007-04-13  8:52       ` Nick Piggin
2007-04-12  9:08 ` [AppArmor 38/41] AppArmor: Module and LSM hooks jjohansen
2007-04-12 10:21   ` Alan Cox
2007-04-16 21:37     ` John Johansen
2007-04-12  9:08 ` [AppArmor 39/41] AppArmor: Profile loading and manipulation, pathname matching jjohansen
2007-04-12 10:28   ` Alan Cox
2007-04-12 13:46   ` Andi Kleen
2007-04-15 14:21     ` Andreas Gruenbacher
2007-04-16  6:27       ` Andi Kleen
2007-04-16 20:56         ` John Johansen
2007-04-16  7:39       ` Pavel Machek
2007-04-16 22:00       ` Alan Cox
2007-04-16 22:11         ` John Johansen
2007-04-12  9:08 ` [AppArmor 40/41] AppArmor: all the rest jjohansen
2007-04-12 10:32   ` Al Viro
2007-04-12 11:32     ` Al Viro
2007-04-12  9:08 ` [AppArmor 41/41] Add AppArmor LSM to security/Makefile jjohansen
2007-04-12 10:33 ` [AppArmor 00/41] AppArmor security module overview Shaya Potter
2007-04-12 13:50 ` Pavel Machek
2007-04-12 21:13   ` David Wagner
2007-04-16  7:46     ` Pavel Machek
2007-04-16 18:24       ` David Wagner
2007-04-13  8:04 ` Rob Meijer

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).