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 <[EMAIL PROTECTED]>
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,