I found a problem with SELinux on a 2.5.44 kernel generating a kernel Oops when running nfsd. The problem is due to the fact that nfsd does not call fs/file_table.c:get_empty_filp where the file_alloc_security hook function is called, but instead calls fs/file_table.c:init_private_file. So struct file_security_struct is never allocated or initialized. Upon further checking, the only other place where init_private_file is called is in fs/exportfs/expfs.c:get_name. This problem was not previously encountered because of the reliance file_precondition. The attached patches add file_alloc_security calls in init_private_file, and file_free_security calls in init_private_file (if an error occurs), fs/nfsd/vfs.c:nfsd_close, and get_name. The patches have been committed to the sourceforge selinux CVS tree. By placing the file_alloc_security in init_private_file, we ensure that all file structures have allocated security fields so we will not get a kernel Oops. We could still potentially have a memory leak if an out-of-tree kernel module uses init_private_file, but doesn't use the file_alloc_security hook. There was the same potential for a memory leak when file_precondition was used. -- Jim Carter Information Assurance Research Group National Security Agency Index: lsm-2.4/fs/file_table.c =================================================================== RCS file: /cvs/lsm/lsm-2.4/fs/file_table.c,v retrieving revision 1.6 diff -u -r1.6 file_table.c --- lsm-2.4/fs/file_table.c 2002/07/08 11:18:42 1.6 +++ lsm-2.4/fs/file_table.c 2002/10/30 17:59:21 @@ -91,6 +91,7 @@ */ int init_private_file(struct file *filp, struct dentry *dentry, int mode) { + int error; memset(filp, 0, sizeof(*filp)); filp->f_mode = mode; atomic_set(&filp->f_count, 1); @@ -98,9 +99,15 @@ filp->f_uid = current->fsuid; filp->f_gid = current->fsgid; filp->f_op = dentry->d_inode->i_fop; - if (filp->f_op->open) - return filp->f_op->open(dentry->d_inode, filp); - else + error = security_ops->file_alloc_security(filp); + if (error) + return error; + if (filp->f_op->open) { + error = filp->f_op->open(dentry->d_inode, filp); + if (error) + security_ops->file_free_security(filp); + return error; + } else return 0; } Index: lsm-2.4/fs/nfsd/nfsfh.c =================================================================== RCS file: /cvs/lsm/lsm-2.4/fs/nfsd/nfsfh.c,v retrieving revision 1.1.1.8 diff -u -r1.1.1.8 nfsfh.c --- lsm-2.4/fs/nfsd/nfsfh.c 2002/08/05 13:41:03 1.1.1.8 +++ lsm-2.4/fs/nfsd/nfsfh.c 2002/10/30 17:59:40 @@ -115,6 +115,7 @@ out_close: if (file.f_op->release) file.f_op->release(dir, &file); + security_ops->file_free_security(&file); out: return error; } Index: lsm-2.4/security/selinux/psid.c =================================================================== RCS file: /cvs/lsm/lsm-2.4/security/selinux/psid.c,v retrieving revision 1.12 diff -u -r1.12 psid.c --- lsm-2.4/security/selinux/psid.c 2002/09/19 18:06:31 1.12 +++ lsm-2.4/security/selinux/psid.c 2002/10/30 17:59:40 @@ -178,6 +178,7 @@ for (i = 0; i < PSEC_NFILES; i++) { if (t->files[i].f_dentry) { dput(t->files[i].f_dentry); + security_ops->file_free_security(&t->files[i]); } } Index: lsm-2.5/fs/file_table.c =================================================================== RCS file: /cvs/lsm/lsm-2.5/fs/file_table.c,v retrieving revision 1.10 diff -u -r1.10 file_table.c --- lsm-2.5/fs/file_table.c 2002/10/16 14:22:37 1.10 +++ lsm-2.5/fs/file_table.c 2002/10/30 18:02:14 @@ -95,6 +95,7 @@ */ int init_private_file(struct file *filp, struct dentry *dentry, int mode) { + int error; memset(filp, 0, sizeof(*filp)); filp->f_mode = mode; atomic_set(&filp->f_count, 1); @@ -102,9 +103,15 @@ filp->f_uid = current->fsuid; filp->f_gid = current->fsgid; filp->f_op = dentry->d_inode->i_fop; - if (filp->f_op->open) - return filp->f_op->open(dentry->d_inode, filp); - else + error = security_ops->file_alloc_security(filp); + if (error) + return error; + if (filp->f_op->open) { + error = filp->f_op->open(dentry->d_inode, filp); + if (error) + security_ops->file_free_security(filp); + return error; + } else return 0; } Index: lsm-2.5/fs/nfsd/vfs.c =================================================================== RCS file: /cvs/lsm/lsm-2.5/fs/nfsd/vfs.c,v retrieving revision 1.1.1.16 diff -u -r1.1.1.16 vfs.c --- lsm-2.5/fs/nfsd/vfs.c 2002/10/21 18:23:22 1.1.1.16 +++ lsm-2.5/fs/nfsd/vfs.c 2002/10/30 18:02:35 @@ -490,6 +490,7 @@ if (filp->f_op->release) filp->f_op->release(inode, filp); + security_ops->file_free_security(filp); if (filp->f_mode & FMODE_WRITE) put_write_access(inode); } Index: lsm-2.5/fs/exportfs/expfs.c =================================================================== RCS file: /cvs/lsm/lsm-2.5/fs/exportfs/expfs.c,v retrieving revision 1.1.1.8 diff -u -r1.1.1.8 expfs.c --- lsm-2.5/fs/exportfs/expfs.c 2002/10/14 12:14:46 1.1.1.8 +++ lsm-2.5/fs/exportfs/expfs.c 2002/10/30 18:02:44 @@ -383,6 +383,7 @@ out_close: if (file.f_op->release) file.f_op->release(dir, &file); + security_ops->file_free_security(&file); out: return error; } Index: lsm-2.5/security/selinux/psid.c =================================================================== RCS file: /cvs/lsm/lsm-2.5/security/selinux/psid.c,v retrieving revision 1.14 diff -u -r1.14 psid.c --- lsm-2.5/security/selinux/psid.c 2002/09/19 18:08:30 1.14 +++ lsm-2.5/security/selinux/psid.c 2002/10/30 18:02:44 @@ -179,6 +179,7 @@ for (i = 0; i < PSEC_NFILES; i++) { if (t->files[i].f_dentry) { dput(t->files[i].f_dentry); + security_ops->file_free_security(&t->files[i]); } } _______________________________________________ linux-security-module mailing list linux-security-moduleat_private http://mail.wirex.com/mailman/listinfo/linux-security-module
This archive was generated by hypermail 2b30 : Wed Oct 30 2002 - 14:29:58 PST