lkml.org 
[lkml]   [2004]   [Dec]   [7]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patches in this message
/
Date
From
SubjectRe: 2.6.10-rc2-mm4
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Stephen Smalley wrote:
| On Wed, 2004-12-01 at 18:32, Jeffrey Mahoney wrote:
|
|>I took some more time to find a more optimal solution. Since ReiserFS is
|>currently the only filesystem that cares about this, it's far easier
to keep
|>the whole mess internal to ReiserFS. The issue isn't about the treating of
|>"private" files in reiserfs, but rather just to avoid the looping of xattr
|>calls that selinux would create.
|
|
| No. It is also about avoiding applying permission checks to these
| "private" inodes when reiserfs performs operations on them, e.g. when
| __get_xa_root() does a lookup_one_len(), there is ultimately a call to
| permission(inode, MAY_EXEC, nd), which triggers a security hook call,
| and SELinux will view this as an attempt by the current process to
| access the private directory. Simply disabling getxattr/setxattr for
| the private inodes won't change this, and you can't assume that most
| processes have permission to access the default file context (in fact,
| in a strict policy, that won't be the case).
|
| Chris' suggestion of exporting this private flag via i_flags and having
| the VFS and/or security framework skip the security hook calls for such
| inodes is more reasonable, and should yield the same behavior as that
| current patchset (just without the extra security hook and the
| filesystem and SELinux-specific private flags).


Ok, well I have a test version of this up and running. It's ugly, but I
don't think any solution to this problem will be pretty. It just hooks
into include/linux/security.h so that all the individual callers don't
need to be special cased.

However, selinux itself accesses inode lists internally that circumvent
this. I believe I caught the major case that causes this, but I'd prefer
someone with more intimate knowledge of selinux verify.

Attached are four patches:
01-vfs-private-flag.diff
~ - adds the S_PRIVATE flag and adds use to security
02-vfs-private-selinux.diff
~ -internal inode loop needs IS_PRIVATE test
03-reiserfs-priv-abstract.diff
~ - private inode abstracted to static inline
04-vfs-private-reiserfs.diff
~ - change reiserfs to use S_PRIVATE

- -Jeff

- --
Jeff Mahoney
SuSE Labs
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.5 (GNU/Linux)
Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org

iD8DBQFBtgsPLPWxlyuTD7IRAm3PAJ9K5lOebus6pY/nkpVQabv9AlXOKwCbBXZw
P94N38RrkdOGuWs19Erbj7I=
=VpuN
-----END PGP SIGNATURE-----
From: Jeff Mahoney <jeffm@suse.com>
Subject: [PATCH 2/4] selinux: internal inode loop needs IS_PRIVATE test

This patch applies the IS_PRIVATE test to the selinux internal inode loop.

Signed-off-by: Jeff Mahoney <jeffm@suse.com>

diff -ruNpX dontdiff linux-2.6.9.base/security/selinux/hooks.c linux-2.6.9.private/security/selinux/hooks.c
--- linux-2.6.9.base/security/selinux/hooks.c 2004-11-19 14:40:58.000000000 -0500
+++ linux-2.6.9.private/security/selinux/hooks.c 2004-12-01 14:38:50.000000000 -0500
@@ -595,7 +595,8 @@ next_inode:
spin_unlock(&sbsec->isec_lock);
inode = igrab(inode);
if (inode) {
- inode_doinit(inode);
+ if (!IS_PRIVATE (inode))
+ inode_doinit(inode);
iput(inode);
}
spin_lock(&sbsec->isec_lock);From: Jeff Mahoney <jeffm@suse.com>
Subject: [PATCH 1/4] vfs: adds the S_PRIVATE flag and adds use to security

This patch adds an S_PRIVATE flag to inode->i_flags to mark an inode as
filesystem-internal. As such, it should be excepted from the security
infrastructure to allow the filesystem to perform its own access control.

Signed-off-by: Jeff Mahoney <jeffm@suse.com>

diff -ruNpX dontdiff linux-2.6.9.base/include/linux/fs.h linux-2.6.9.private/include/linux/fs.h
--- linux-2.6.9.base/include/linux/fs.h 2004-11-19 14:40:56.000000000 -0500
+++ linux-2.6.9.private/include/linux/fs.h 2004-11-30 15:04:24.000000000 -0500
@@ -146,6 +146,7 @@ extern int leases_enable, dir_notify_ena
#define S_DIRSYNC 64 /* Directory modifications are synchronous */
#define S_NOCMTIME 128 /* Do not update file c/mtime */
#define S_SWAPFILE 256 /* Do not truncate: swapon got its bmaps */
+#define S_PRIVATE 512 /* Inode is fs-internal */

/*
* Note that nosuid etc flags are inode-specific: setting some file-system
@@ -180,6 +181,7 @@ extern int leases_enable, dir_notify_ena
#define IS_DEADDIR(inode) ((inode)->i_flags & S_DEAD)
#define IS_NOCMTIME(inode) ((inode)->i_flags & S_NOCMTIME)
#define IS_SWAPFILE(inode) ((inode)->i_flags & S_SWAPFILE)
+#define IS_PRIVATE(inode) ((inode)->i_flags & S_PRIVATE)

/* the read-only stuff doesn't really belong here, but any other place is
probably as bad and I don't want to create yet another include file. */
diff -ruNpX dontdiff linux-2.6.9.base/include/linux/security.h linux-2.6.9.private/include/linux/security.h
--- linux-2.6.9.base/include/linux/security.h 2004-08-14 01:37:30.000000000 -0400
+++ linux-2.6.9.private/include/linux/security.h 2004-12-01 14:14:07.000000000 -0500
@@ -1406,11 +1406,15 @@ static inline void security_sb_post_pivo

static inline int security_inode_alloc (struct inode *inode)
{
+ if (unlikely (IS_PRIVATE (inode)))
+ return 0;
return security_ops->inode_alloc_security (inode);
}

static inline void security_inode_free (struct inode *inode)
{
+ if (unlikely (IS_PRIVATE (inode)))
+ return;
security_ops->inode_free_security (inode);
}

@@ -1418,6 +1422,8 @@ static inline int security_inode_create
struct dentry *dentry,
int mode)
{
+ if (unlikely (IS_PRIVATE (dir)))
+ return 0;
return security_ops->inode_create (dir, dentry, mode);
}

@@ -1425,6 +1431,8 @@ static inline void security_inode_post_c
struct dentry *dentry,
int mode)
{
+ if (unlikely (IS_PRIVATE (dentry->d_inode)))
+ return;
security_ops->inode_post_create (dir, dentry, mode);
}

@@ -1432,6 +1440,8 @@ static inline int security_inode_link (s
struct inode *dir,
struct dentry *new_dentry)
{
+ if (unlikely (IS_PRIVATE (old_dentry->d_inode)))
+ return 0;
return security_ops->inode_link (old_dentry, dir, new_dentry);
}

@@ -1439,12 +1449,16 @@ static inline void security_inode_post_l
struct inode *dir,
struct dentry *new_dentry)
{
+ if (unlikely (IS_PRIVATE (new_dentry->d_inode)))
+ return;
security_ops->inode_post_link (old_dentry, dir, new_dentry);
}

static inline int security_inode_unlink (struct inode *dir,
struct dentry *dentry)
{
+ if (unlikely (IS_PRIVATE (dentry->d_inode)))
+ return 0;
return security_ops->inode_unlink (dir, dentry);
}

@@ -1452,6 +1466,8 @@ static inline int security_inode_symlink
struct dentry *dentry,
const char *old_name)
{
+ if (unlikely (IS_PRIVATE (dir)))
+ return 0;
return security_ops->inode_symlink (dir, dentry, old_name);
}

@@ -1459,6 +1475,8 @@ static inline void security_inode_post_s
struct dentry *dentry,
const char *old_name)
{
+ if (unlikely (IS_PRIVATE (dentry->d_inode)))
+ return;
security_ops->inode_post_symlink (dir, dentry, old_name);
}

@@ -1466,6 +1484,8 @@ static inline int security_inode_mkdir (
struct dentry *dentry,
int mode)
{
+ if (unlikely (IS_PRIVATE (dir)))
+ return 0;
return security_ops->inode_mkdir (dir, dentry, mode);
}

@@ -1473,12 +1493,16 @@ static inline void security_inode_post_m
struct dentry *dentry,
int mode)
{
+ if (unlikely (IS_PRIVATE (dentry->d_inode)))
+ return;
security_ops->inode_post_mkdir (dir, dentry, mode);
}

static inline int security_inode_rmdir (struct inode *dir,
struct dentry *dentry)
{
+ if (unlikely (IS_PRIVATE (dentry->d_inode)))
+ return 0;
return security_ops->inode_rmdir (dir, dentry);
}

@@ -1486,6 +1510,8 @@ static inline int security_inode_mknod (
struct dentry *dentry,
int mode, dev_t dev)
{
+ if (unlikely (IS_PRIVATE (dir)))
+ return 0;
return security_ops->inode_mknod (dir, dentry, mode, dev);
}

@@ -1493,6 +1519,8 @@ static inline void security_inode_post_m
struct dentry *dentry,
int mode, dev_t dev)
{
+ if (unlikely (IS_PRIVATE (dentry->d_inode)))
+ return;
security_ops->inode_post_mknod (dir, dentry, mode, dev);
}

@@ -1501,6 +1529,9 @@ static inline int security_inode_rename
struct inode *new_dir,
struct dentry *new_dentry)
{
+ 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);
}
@@ -1510,83 +1541,114 @@ static inline void security_inode_post_r
struct inode *new_dir,
struct dentry *new_dentry)
{
+ if (unlikely (IS_PRIVATE (old_dentry->d_inode) ||
+ (new_dentry->d_inode && IS_PRIVATE (new_dentry->d_inode))))
+ return;
security_ops->inode_post_rename (old_dir, old_dentry,
new_dir, new_dentry);
}

static inline int security_inode_readlink (struct dentry *dentry)
{
+ if (unlikely (IS_PRIVATE (dentry->d_inode)))
+ return 0;
return security_ops->inode_readlink (dentry);
}

static inline int security_inode_follow_link (struct dentry *dentry,
struct nameidata *nd)
{
+ if (unlikely (IS_PRIVATE (dentry->d_inode)))
+ return 0;
return security_ops->inode_follow_link (dentry, nd);
}

static inline int security_inode_permission (struct inode *inode, int mask,
struct nameidata *nd)
{
+ if (unlikely (IS_PRIVATE (inode)))
+ return 0;
return security_ops->inode_permission (inode, mask, nd);
}

static inline int security_inode_setattr (struct dentry *dentry,
struct iattr *attr)
{
+ if (unlikely (IS_PRIVATE (dentry->d_inode)))
+ return 0;
return security_ops->inode_setattr (dentry, attr);
}

static inline int security_inode_getattr (struct vfsmount *mnt,
struct dentry *dentry)
{
+ if (unlikely (IS_PRIVATE (dentry->d_inode)))
+ return 0;
return security_ops->inode_getattr (mnt, dentry);
}

static inline void security_inode_delete (struct inode *inode)
{
+ if (unlikely (IS_PRIVATE (inode)))
+ return;
security_ops->inode_delete (inode);
}

static inline int security_inode_setxattr (struct dentry *dentry, 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);
}

static inline void security_inode_post_setxattr (struct dentry *dentry, 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);
}

static inline int security_inode_getxattr (struct dentry *dentry, char *name)
{
+ if (unlikely (IS_PRIVATE (dentry->d_inode)))
+ return 0;
return security_ops->inode_getxattr (dentry, name);
}

static inline int security_inode_listxattr (struct dentry *dentry)
{
+ if (unlikely (IS_PRIVATE (dentry->d_inode)))
+ return 0;
return security_ops->inode_listxattr (dentry);
}

static inline int security_inode_removexattr (struct dentry *dentry, char *name)
{
+ if (unlikely (IS_PRIVATE (dentry->d_inode)))
+ return 0;
return security_ops->inode_removexattr (dentry, name);
}

static inline int security_inode_getsecurity(struct dentry *dentry, const char *name, void *buffer, size_t size)
{
+ if (unlikely (IS_PRIVATE (dentry->d_inode)))
+ return 0;
return security_ops->inode_getsecurity(dentry, name, buffer, size);
}

static inline int security_inode_setsecurity(struct dentry *dentry, const char *name, const void *value, size_t size, int flags)
{
+ if (unlikely (IS_PRIVATE (dentry->d_inode)))
+ return 0;
return security_ops->inode_setsecurity(dentry, name, value, size, flags);
}

static inline int security_inode_listsecurity(struct dentry *dentry, char *buffer)
{
+ if (unlikely (IS_PRIVATE (dentry->d_inode)))
+ return 0;
return security_ops->inode_listsecurity(dentry, buffer);
}

@@ -1863,6 +1925,8 @@ static inline int security_sem_semop (st

static inline void security_d_instantiate (struct dentry *dentry, struct inode *inode)
{
+ if (unlikely (inode && IS_PRIVATE (inode)))
+ return;
security_ops->d_instantiate (dentry, inode);
}
From: Jeff Mahoney <jeffm@suse.com>
Subject: [PATCH 3/4] reiserfs: private inode abstracted to static inline

This patch moves the assignment of i_priv_object to a static inline. This
is in preparation for selinux support in reiserfs.

Signed-off-by: Jeff Mahoney <jeffm@suse.com>

diff -ruNpX dontdiff linux-2.6.9/fs/reiserfs/inode.c linux-2.6.9.base/fs/reiserfs/inode.c
--- linux-2.6.9/fs/reiserfs/inode.c 2004-11-19 14:40:53.000000000 -0500
+++ linux-2.6.9.base/fs/reiserfs/inode.c 2004-11-30 16:03:42.000000000 -0500
@@ -1804,6 +1804,8 @@ int reiserfs_new_inode (struct reiserfs_
} else if (inode->i_sb->s_flags & MS_POSIXACL) {
reiserfs_warning (inode->i_sb, "ACLs aren't enabled in the fs, "
"but vfs thinks they are!");
+ } else if (is_reiserfs_priv_object (dir)) {
+ reiserfs_mark_inode_private (inode);
}

insert_inode_hash (inode);
diff -ruNpX dontdiff linux-2.6.9/fs/reiserfs/namei.c linux-2.6.9.base/fs/reiserfs/namei.c
--- linux-2.6.9/fs/reiserfs/namei.c 2004-08-14 01:37:14.000000000 -0400
+++ linux-2.6.9.base/fs/reiserfs/namei.c 2004-11-30 16:03:42.000000000 -0500
@@ -352,7 +352,7 @@ static struct dentry * reiserfs_lookup (

/* Propogate the priv_object flag so we know we're in the priv tree */
if (is_reiserfs_priv_object (dir))
- REISERFS_I(inode)->i_flags |= i_priv_object;
+ reiserfs_mark_inode_private (inode);
}
reiserfs_write_unlock(dir->i_sb);
if ( retval == IO_ERROR ) {
diff -ruNpX dontdiff linux-2.6.9/fs/reiserfs/xattr_acl.c linux-2.6.9.base/fs/reiserfs/xattr_acl.c
--- linux-2.6.9/fs/reiserfs/xattr_acl.c 2004-11-19 14:40:53.000000000 -0500
+++ linux-2.6.9.base/fs/reiserfs/xattr_acl.c 2004-11-30 16:03:42.000000000 -0500
@@ -337,7 +337,7 @@ reiserfs_inherit_default_acl (struct ino
* would be useless since permissions are ignored, and a pain because
* it introduces locking cycles */
if (is_reiserfs_priv_object (dir)) {
- REISERFS_I(inode)->i_flags |= i_priv_object;
+ reiserfs_mark_inode_private (inode);
goto apply_umask;
}

diff -ruNpX dontdiff linux-2.6.9/fs/reiserfs/xattr.c linux-2.6.9.base/fs/reiserfs/xattr.c
--- linux-2.6.9/fs/reiserfs/xattr.c 2004-11-19 14:40:53.000000000 -0500
+++ linux-2.6.9.base/fs/reiserfs/xattr.c 2004-12-07 13:54:17.336459088 -0500
@@ -181,8 +181,6 @@ open_xa_dir (const struct inode *inode,
dput (xadir);
return ERR_PTR (-ENODATA);
}
- /* Newly created object.. Need to mark it private */
- REISERFS_I(xadir->d_inode)->i_flags |= i_priv_object;
}

dput (xaroot);
@@ -230,8 +228,6 @@ get_xa_file_dentry (const struct inode *
dput (xafile);
goto out;
}
- /* Newly created object.. Need to mark it private */
- REISERFS_I(xafile->d_inode)->i_flags |= i_priv_object;
}

out:
@@ -1316,7 +1312,7 @@ reiserfs_xattr_init (struct super_block

if (!err && dentry) {
s->s_root->d_op = &xattr_lookup_poison_ops;
- REISERFS_I(dentry->d_inode)->i_flags |= i_priv_object;
+ reiserfs_mark_inode_private (dentry->d_inode);
REISERFS_SB(s)->priv_root = dentry;
} else if (!(mount_flags & MS_RDONLY)) { /* xattrs are unavailable */
/* If we're read-only it just means that the dir hasn't been
diff -ruNpX dontdiff linux-2.6.9/include/linux/reiserfs_xattr.h linux-2.6.9.base/include/linux/reiserfs_xattr.h
--- linux-2.6.9/include/linux/reiserfs_xattr.h 2004-08-14 01:38:11.000000000 -0400
+++ linux-2.6.9.base/include/linux/reiserfs_xattr.h 2004-11-30 16:03:42.000000000 -0500
@@ -103,6 +103,12 @@ reiserfs_read_unlock_xattr_i(struct inod
up_read (&REISERFS_I(inode)->xattr_sem);
}

+static inline void
+reiserfs_mark_inode_private(struct inode *inode)
+{
+ REISERFS_I(inode)->i_flags |= i_priv_object;
+}
+
#else

#define is_reiserfs_priv_object(inode) 0From: Jeff Mahoney <jeffm@suse.com>
Subject: [PATCH 4/4] reiserfs: change reiserfs to use S_PRIVATE

This patch changes reiserfs to use the VFS level private inode flags, and
eliminates the old reiserfs private inode flag.

Signed-off-by: Jeff Mahoney <jeffm@suse.com>

diff -ruNpX dontdiff linux-2.6.9.base/include/linux/reiserfs_xattr.h linux-2.6.9.private/include/linux/reiserfs_xattr.h
--- linux-2.6.9.base/include/linux/reiserfs_xattr.h 2004-11-30 16:03:42.000000000 -0500
+++ linux-2.6.9.private/include/linux/reiserfs_xattr.h 2004-12-07 14:23:43.266996840 -0500
@@ -31,7 +31,7 @@ struct reiserfs_xattr_handler {


#ifdef CONFIG_REISERFS_FS_XATTR
-#define is_reiserfs_priv_object(inode) (REISERFS_I(inode)->i_flags & i_priv_object)
+#define is_reiserfs_priv_object(inode) IS_PRIVATE(inode)
#define has_xattr_dir(inode) (REISERFS_I(inode)->i_flags & i_has_xattr_dir)
ssize_t reiserfs_getxattr (struct dentry *dentry, const char *name,
void *buffer, size_t size);
@@ -106,7 +106,7 @@ reiserfs_read_unlock_xattr_i(struct inod
static inline void
reiserfs_mark_inode_private(struct inode *inode)
{
- REISERFS_I(inode)->i_flags |= i_priv_object;
+ inode->i_flags |= S_PRIVATE;
}

#else
diff -ruNpX dontdiff linux-2.6.9.base/include/linux/reiserfs_fs_i.h linux-2.6.9.private/include/linux/reiserfs_fs_i.h
--- linux-2.6.9.base/include/linux/reiserfs_fs_i.h 2004-11-19 14:40:57.000000000 -0500
+++ linux-2.6.9.private/include/linux/reiserfs_fs_i.h 2004-12-07 14:25:40.259211320 -0500
@@ -23,9 +23,8 @@ typedef enum {
space on crash with some files open, but unlinked. */
i_link_saved_unlink_mask = 0x0010,
i_link_saved_truncate_mask = 0x0020,
- i_priv_object = 0x0080,
- i_has_xattr_dir = 0x0100,
- i_data_log = 0x0200,
+ i_has_xattr_dir = 0x0040,
+ i_data_log = 0x0080,
} reiserfs_inode_flags;

\
 
 \ /
  Last update: 2005-03-22 14:08    [W:0.512 / U:0.344 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site