[patch 2/7] BSD Secure Levels: move bd claim from inode to filp

From: Michael Halcrow
Date: Tue May 17 2005 - 10:28:33 EST


This is the second in a series of seven 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. Chris Wright observed that
using filp as a holder addresses the fact that multiple processes can
share an fd.

Signed off by: Michael Halcrow <mhalcrow@xxxxxxxxxx>

Index: linux-2.6.12-rc4-mm2-seclvl/security/seclvl.c
===================================================================
--- linux-2.6.12-rc4-mm2-seclvl.orig/security/seclvl.c 2005-05-16 16:23:15.000000000 -0500
+++ linux-2.6.12-rc4-mm2-seclvl/security/seclvl.c 2005-05-16 16:27:27.000000000 -0500
@@ -487,46 +487,34 @@
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)) {
+ if (bd_claim(bdev, filp)) {
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 = filp;
}
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 +522,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",
@@ -565,15 +553,23 @@
return 0;
}

-/* release busied block devices */
+/**
+ * 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);
+ if (dentry && (filp->f_mode & FMODE_WRITE)) {
+ struct inode *inode = dentry->d_inode;
+ if (inode && S_ISBLK(inode->i_mode)
+ && filp->f_security == filp) {
+ struct block_device *bdev = inode->i_bdev;
+ if (bdev) {
+ bd_release(bdev);
+ blkdev_put(bdev);
+ filp->f_security = NULL;
+ }
+ }
}
}

@@ -596,7 +592,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,
.file_free_security = seclvl_file_free_security,
.settime = seclvl_settime,
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/