From mboxrd@z Thu Jan 1 00:00:00 1970 From: "Timothy R. Chavez" Subject: [RFC][PATCH 1/2] file system auditing Date: Tue, 5 Apr 2005 17:04:30 -0500 Message-ID: <200504051704.30400.tinytim@us.ibm.com> Mime-Version: 1.0 Content-Type: text/plain; charset=iso-8859-1 Content-Transfer-Encoding: QUOTED-PRINTABLE Return-path: Received: from e34.co.us.ibm.com ([32.97.110.132]:63934 "EHLO e34.co.us.ibm.com") by vger.kernel.org with ESMTP id S261983AbVDEWDs convert rfc822-to-8bit (ORCPT ); Tue, 5 Apr 2005 18:03:48 -0400 Received: from d03relay04.boulder.ibm.com (d03relay04.boulder.ibm.com [9.17.195.106]) by e34.co.us.ibm.com (8.12.10/8.12.9) with ESMTP id j35M3i5b382798 for ; Tue, 5 Apr 2005 18:03:44 -0400 Received: from d03av02.boulder.ibm.com (d03av02.boulder.ibm.com [9.17.195.168]) by d03relay04.boulder.ibm.com (8.12.10/NCO/VER6.6) with ESMTP id j35M3iHO183440 for ; Tue, 5 Apr 2005 16:03:44 -0600 Received: from d03av02.boulder.ibm.com (loopback [127.0.0.1]) by d03av02.boulder.ibm.com (8.12.11/8.12.11) with ESMTP id j35M3iaK027088 for ; Tue, 5 Apr 2005 16:03:44 -0600 Received: from dyn94194164.austin.ibm.com (dyn94194164.austin.ibm.com [9.41.94.164]) by d03av02.boulder.ibm.com (8.12.11/8.12.11) with ESMTP id j35M3i3p027070 for ; Tue, 5 Apr 2005 16:03:44 -0600 To: linux-fsdevel@vger.kernel.org Content-Disposition: inline Sender: linux-fsdevel-owner@vger.kernel.org List-Id: linux-fsdevel.vger.kernel.org Hello, The audit subsystem is currently incapable of auditing a file system ob= ject=20 based on its location and name. =A0This is critical for auditing well-d= efined=20 and security-relevant locations such as /etc/shadow, where the file is=20 re-created on each transaction, and cannot rely on the (device, inode)-= based=20 filters to ensure persistence of auditing across transactions. This pat= ch adds=20 the necessary functionality to the audit subsystem and VFS to support f= ile=20 system auditing in which an object is audited based on its location and= name. =A0 This work is being done to make the audit subsystem compliant with Comm= on=20 Criteria's Controlled Access Protection Profile (CAPP) specification. The patch has been split in two for RFC. [PATCH 1/2] The first patch consists of the file system hooks and appears at the bo= ttom of=20 this message preceded by brief explanations of each hook. =A0The quoted= =20 terminology is defined in the high-level overview of the design that's = been=20 included with the second patch in the next message. [PATCH 2/2] The second patch consists of the file system auditing implementation pr= eceded=20 by a high-level overview of the design. The entire patch was diffed against linux-2.6.11-rc2-mm1 -tim ---- 1. =A0Setup Placement in fs/inode.c=20 audit_inode_alloc()/audit_inode_free(): These hooks are responsible for allocating and deallocating inode audit= data. 2. =A0Management Management of "watches" starts at the dentry level. Placement in fs/dcache.c Initial setup: d_instantiate()/d_splice_alias() : These hooks cover initial audit setup for inodes that are newly created= and=20 for existing inodes when they are first looked up, prior to becoming=20 accessible via the dcache. Update: __d_lookup(): This hook covers updating the inode audit data if necessary upon subseq= uent=20 lookups when the inode is already accessible via dcache, both to reflec= t=20 removal of "watches" and to handle changes in state since the initial s= etup. d_move(): This hook covers resetting the inode audit data and updating it accordi= ngly=20 post-move. Deletion: dentry_iput(): This hook covers resetting the inode audit data if the dentry being del= eted is=20 at a "watch point". 3. =A0Notification Any time we access a "watched" object we are auditable. =A0These hooks = are used=20 to notify the audit subsystem of relevant access. =A0 Placement in fs/namei.c. Permissions: permission()/exec_permission_lite(): Notify the audit subsystem when a "watched" object is consulted about=20 permissions requirements. Creation: vfs_link()/symlink()/create()/mkdir()/mknod(): Notify the audit subsystem when an object has successfully manifested a= t a=20 "watch point".=20 Deletion: may_delete() [vfs_unlink()/rmdir()]:=20 Notify the audit subsystem when an object attempts to leave a "watch po= int". =A0 This hook appears in may_delete() after its been determined the object = has an=20 inode. Note: =A0We are unable to use may_create() in a similar fashion to may_= delete()=20 because the object should not have an inode associated with it yet. Rename: may_delete(),vfs_rename_other()/rename_dir(): Notify the audit subsystem when an object has been moved out of a "watc= h=20 point" using the may_delete() hook. =A0Notify the audit subsystem when = an=20 object already exists at our destination and our destination is a "watc= h=20 point". =A0Notify the audit subsystem when an object moves in to a "wat= ch=20 point" using the vfs_rename_other/rename_dir() hooks. diff -Nurp linux-2.6.12-rc2-mm1/fs/dcache.c linux-2.6.12-rc2-mm1~audit/= fs/dcache.c --- linux-2.6.12-rc2-mm1/fs/dcache.c 2005-04-05 14:05:16.000000000 -050= 0 +++ linux-2.6.12-rc2-mm1~audit/fs/dcache.c 2005-04-05 13:16:04.00000000= 0 -0500 @@ -32,6 +32,7 @@ #include #include #include +#include =20 /* #define DCACHE_DEBUG 1 */ =20 @@ -97,6 +98,7 @@ static inline void dentry_iput(struct de { struct inode *inode =3D dentry->d_inode; if (inode) { + audit_attach_watch(dentry, 1); dentry->d_inode =3D NULL; list_del_init(&dentry->d_alias); spin_unlock(&dentry->d_lock); @@ -802,6 +804,7 @@ void d_instantiate(struct dentry *entry, if (inode) list_add(&entry->d_alias, &inode->i_dentry); entry->d_inode =3D inode; + audit_attach_watch(entry, 0); spin_unlock(&dcache_lock); security_d_instantiate(entry, inode); } @@ -978,6 +981,7 @@ struct dentry *d_splice_alias(struct ino new =3D __d_find_alias(inode, 1); if (new) { BUG_ON(!(new->d_flags & DCACHE_DISCONNECTED)); + audit_attach_watch(new, 0); spin_unlock(&dcache_lock); security_d_instantiate(new, inode); d_rehash(dentry); @@ -987,6 +991,7 @@ struct dentry *d_splice_alias(struct ino /* d_instantiate takes dcache_lock, so we do it by hand */ list_add(&dentry->d_alias, &inode->i_dentry); dentry->d_inode =3D inode; + audit_attach_watch(dentry, 0); spin_unlock(&dcache_lock); security_d_instantiate(dentry, inode); d_rehash(dentry); @@ -1090,6 +1095,7 @@ struct dentry * __d_lookup(struct dentry if (!d_unhashed(dentry)) { atomic_inc(&dentry->d_count); found =3D dentry; + audit_attach_watch(found, 0); } spin_unlock(&dentry->d_lock); break; @@ -1299,6 +1305,8 @@ void d_move(struct dentry * dentry, stru spin_lock(&target->d_lock); } =20 + audit_attach_watch(dentry, 1); + /* Move the dentry to the target hash queue, if on different bucket *= / if (dentry->d_flags & DCACHE_UNHASHED) goto already_unhashed; @@ -1332,6 +1340,7 @@ already_unhashed: list_add(&target->d_child, &target->d_parent->d_subdirs); } =20 + audit_attach_watch(dentry, 0); list_add(&dentry->d_child, &dentry->d_parent->d_subdirs); spin_unlock(&target->d_lock); spin_unlock(&dentry->d_lock); diff -Nurp linux-2.6.12-rc2-mm1/fs/inode.c linux-2.6.12-rc2-mm1~audit/f= s/inode.c --- linux-2.6.12-rc2-mm1/fs/inode.c 2005-04-05 14:06:28.000000000 -0500 +++ linux-2.6.12-rc2-mm1~audit/fs/inode.c 2005-04-05 13:16:04.000000000= -0500 @@ -22,6 +22,7 @@ #include #include #include +#include =20 /* * This is needed for the following functions: @@ -140,9 +141,11 @@ static struct inode *alloc_inode(struct=20 inode->i_bdev =3D NULL; inode->i_cdev =3D NULL; inode->i_rdev =3D 0; + inode->i_audit =3D NULL; inode->i_security =3D NULL; inode->dirtied_when =3D 0; - if (security_inode_alloc(inode)) { + if (audit_inode_alloc(inode) || security_inode_alloc(inode)) { + audit_inode_free(inode); if (inode->i_sb->s_op->destroy_inode) inode->i_sb->s_op->destroy_inode(inode); else @@ -180,6 +183,7 @@ void destroy_inode(struct inode *inode)=20 { if (inode_has_buffers(inode)) BUG(); + audit_inode_free(inode); security_inode_free(inode); if (inode->i_sb->s_op->destroy_inode) inode->i_sb->s_op->destroy_inode(inode); diff -Nurp linux-2.6.12-rc2-mm1/fs/namei.c linux-2.6.12-rc2-mm1~audit/f= s/namei.c --- linux-2.6.12-rc2-mm1/fs/namei.c 2005-04-05 14:06:28.000000000 -0500 +++ linux-2.6.12-rc2-mm1~audit/fs/namei.c 2005-04-05 13:16:04.000000000= -0500 @@ -225,6 +225,8 @@ int permission(struct inode *inode, int=20 { int retval, submask; =20 + audit_notify_watch(inode, mask); + if (mask & MAY_WRITE) { umode_t mode =3D inode->i_mode; =20 @@ -358,6 +360,8 @@ static inline int exec_permission_lite(s if (inode->i_op && inode->i_op->permission) return -EAGAIN; =20 + audit_notify_watch(inode, MAY_EXEC); + if (current->fsuid =3D=3D inode->i_uid) mode >>=3D 6; else if (in_group_p(inode->i_gid)) @@ -1172,6 +1176,8 @@ static inline int may_delete(struct inod =20 BUG_ON(victim->d_parent->d_inode !=3D dir); =20 + audit_notify_watch(victim->d_inode, MAY_WRITE); + error =3D permission(dir,MAY_WRITE | MAY_EXEC, NULL); if (error) return error; @@ -1296,6 +1302,7 @@ int vfs_create(struct inode *dir, struct DQUOT_INIT(dir); error =3D dir->i_op->create(dir, dentry, mode, nd); if (!error) { + audit_notify_watch(dentry->d_inode, MAY_WRITE); fsnotify_create(dir, dentry->d_name.name); security_inode_post_create(dir, dentry, mode); } @@ -1601,6 +1608,7 @@ int vfs_mknod(struct inode *dir, struct=20 DQUOT_INIT(dir); error =3D dir->i_op->mknod(dir, dentry, mode, dev); if (!error) { + audit_notify_watch(dentry->d_inode, MAY_WRITE); fsnotify_create(dir, dentry->d_name.name); security_inode_post_mknod(dir, dentry, mode, dev); } @@ -1674,6 +1682,7 @@ int vfs_mkdir(struct inode *dir, struct=20 DQUOT_INIT(dir); error =3D dir->i_op->mkdir(dir, dentry, mode); if (!error) { + audit_notify_watch(dentry->d_inode, MAY_WRITE); fsnotify_mkdir(dir, dentry->d_name.name); security_inode_post_mkdir(dir,dentry, mode); } @@ -1915,6 +1924,7 @@ int vfs_symlink(struct inode *dir, struc DQUOT_INIT(dir); error =3D dir->i_op->symlink(dir, dentry, oldname); if (!error) { + audit_notify_watch(dentry->d_inode, MAY_WRITE); fsnotify_create(dir, dentry->d_name.name); security_inode_post_symlink(dir, dentry, oldname); } @@ -1988,6 +1998,7 @@ int vfs_link(struct dentry *old_dentry,=20 error =3D dir->i_op->link(old_dentry, dir, new_dentry); up(&old_dentry->d_inode->i_sem); if (!error) { + audit_notify_watch(new_dentry->d_inode, MAY_WRITE); fsnotify_create(dir, new_dentry->d_name.name); security_inode_post_link(old_dentry, dir, new_dentry); } @@ -2111,6 +2122,7 @@ int vfs_rename_dir(struct inode *old_dir } if (!error) { d_move(old_dentry,new_dentry); + audit_notify_watch(old_dentry->d_inode, MAY_WRITE); security_inode_post_rename(old_dir, old_dentry, new_dir, new_dentry); } @@ -2139,6 +2151,7 @@ int vfs_rename_other(struct inode *old_d /* The following d_move() should become unconditional */ if (!(old_dir->i_sb->s_type->fs_flags & FS_ODD_RENAME)) d_move(old_dentry, new_dentry); + audit_notify_watch(old_dentry->d_inode, MAY_WRITE); security_inode_post_rename(old_dir, old_dentry, new_dir, new_dentry)= ; } if (target) - To unsubscribe from this list: send the line "unsubscribe linux-fsdevel= " in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html