[PATCH] BSD Secure Levels: claim block dev in file struct rather than inode struct, 2.6.11-rc2-mm1 (3/8)

From: Michael Halcrow
Date: Mon Feb 07 2005 - 14:48:13 EST


This is the third in a series of eight patches to the BSD Secure
Levels LSM. It moves the claim on the block device from the inode
struct to the file struct in order to address a potential
circumvention of the control via hard links to block devices. Thanks
to Serge Hallyn for pointing this out.

Signed off by: Michael Halcrow <mhalcrow@xxxxxxxxxx>
Index: linux-2.6.11-rc2-mm1-modules/security/seclvl.c
===================================================================
--- linux-2.6.11-rc2-mm1-modules.orig/security/seclvl.c 2005-02-03 15:36:43.925683472 -0600
+++ linux-2.6.11-rc2-mm1-modules/security/seclvl.c 2005-02-03 16:41:55.075098384 -0600
@@ -487,46 +487,35 @@
return 0;
}

-/* claim the blockdev to exclude mounters, release on file close */
-static int seclvl_bd_claim(struct inode *inode)
+/**
+ * Claim the blockdev to exclude mounters; release on file close.
+ */
+static int seclvl_bd_claim(struct file * filp)
{
int holder;
struct block_device *bdev = NULL;
- dev_t dev = inode->i_rdev;
+ dev_t dev = filp->f_dentry->d_inode->i_rdev;
bdev = open_by_devnum(dev, FMODE_WRITE);
if (bdev) {
if (bd_claim(bdev, &holder)) {
blkdev_put(bdev);
return -EPERM;
}
- /* claimed, mark it to release on close */
- inode->i_security = current;
+ /* Claimed; mark it to release on close */
+ filp->f_security = current;
}
return 0;
}

-/* release the blockdev if you claimed it */
-static void seclvl_bd_release(struct inode *inode)
-{
- if (inode && S_ISBLK(inode->i_mode) && inode->i_security == current) {
- struct block_device *bdev = inode->i_bdev;
- if (bdev) {
- bd_release(bdev);
- blkdev_put(bdev);
- inode->i_security = NULL;
- }
- }
-}
-
/**
* Security for writes to block devices is regulated by this seclvl
* function. Deny all writes to block devices in seclvl 2. In
* seclvl 1, we only deny writes to *mounted* block devices.
*/
-static int
-seclvl_inode_permission(struct inode *inode, int mask, struct nameidata *nd)
+static int seclvl_file_permission(struct file * filp, int mask)
{
- if (current->pid != 1 && S_ISBLK(inode->i_mode) && (mask & MAY_WRITE)) {
+ if (current->pid != 1 && S_ISBLK(filp->f_dentry->d_inode->i_mode)
+ && (mask & MAY_WRITE)) {
switch (seclvl) {
case 2:
seclvl_printk(1, KERN_WARNING "%s: Write to block "
@@ -534,7 +523,7 @@
__FUNCTION__, seclvl);
return -EPERM;
case 1:
- if (seclvl_bd_claim(inode)) {
+ if (seclvl_bd_claim(filp)) {
seclvl_printk(1, KERN_WARNING "%s: Write to "
"mounted block device denied in "
"secure level [%d]\n",
@@ -549,7 +538,7 @@
/**
* The SUID and SGID bits cannot be set in seclvl >= 1
*/
-static int seclvl_inode_setattr(struct dentry *dentry, struct iattr *iattr)
+static int seclvl_inode_setattr(struct dentry * dentry, struct iattr * iattr)
{
if (seclvl > 0) {
if (dentry && dentry->d_inode
@@ -599,15 +588,23 @@
return 0;
}

-/* release busied block devices */
-static void seclvl_file_free_security(struct file *filp)
+/**
+ * Release busied block devices.
+ */
+static void seclvl_file_free_security(struct file * filp)
{
- struct dentry *dentry = filp->f_dentry;
- struct inode *inode = NULL;
-
- if (dentry) {
- inode = dentry->d_inode;
- seclvl_bd_release(inode);
+ struct dentry * dentry = filp->f_dentry;
+ if (dentry && (filp->f_mode & FMODE_WRITE)) {
+ struct inode * inode = dentry->d_inode;
+ if (inode && S_ISBLK(inode->i_mode)
+ && filp->f_security == current) {
+ struct block_device *bdev = inode->i_bdev;
+ if (bdev) {
+ bd_release(bdev);
+ blkdev_put(bdev);
+ filp->f_security = NULL;
+ }
+ }
}
}

@@ -630,7 +627,7 @@
static struct security_operations seclvl_ops = {
.ptrace = seclvl_ptrace,
.capable = seclvl_capable,
- .inode_permission = seclvl_inode_permission,
+ .file_permission = seclvl_file_permission,
.inode_setattr = seclvl_inode_setattr,
.inode_mknod = seclvl_inode_mknod,
.inode_create = seclvl_inode_create,