diff -NurpP --minimal linux-2.6.19-vs2.1.1.5.1/fs/block_dev.c linux-2.6.19-vs2.1.1.5.2/fs/block_dev.c --- linux-2.6.19-vs2.1.1.5.1/fs/block_dev.c 2006-12-11 01:55:26 +0100 +++ linux-2.6.19-vs2.1.1.5.2/fs/block_dev.c 2006-12-11 23:59:46 +0100 @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include "internal.h" @@ -415,8 +415,7 @@ EXPORT_SYMBOL(bdput); static struct block_device *bd_acquire(struct inode *inode) { struct block_device *bdev; - dev_t rdev; - int ret; + dev_t mdev; spin_lock(&bdev_lock); bdev = inode->i_bdev; @@ -427,13 +426,12 @@ static struct block_device *bd_acquire(s } spin_unlock(&bdev_lock); - rdev = inode->i_rdev; - - ret = vs_map_device(current->vx_info, &rdev); - if (ret) + mdev = inode->i_rdev; + if (!vs_map_blkdev(&mdev, DATTR_OPEN)) return NULL; + inode->i_mdev = mdev; - bdev = bdget(rdev); + bdev = bdget(mdev); if (bdev) { spin_lock(&bdev_lock); if (!inode->i_bdev) { diff -NurpP --minimal linux-2.6.19-vs2.1.1.5.1/fs/char_dev.c linux-2.6.19-vs2.1.1.5.2/fs/char_dev.c --- linux-2.6.19-vs2.1.1.5.1/fs/char_dev.c 2006-12-11 00:36:19 +0100 +++ linux-2.6.19-vs2.1.1.5.2/fs/char_dev.c 2006-12-12 00:12:09 +0100 @@ -20,7 +20,7 @@ #include #include #include -#include +#include #ifdef CONFIG_KMOD #include @@ -368,15 +368,15 @@ int chrdev_open(struct inode * inode, st p = inode->i_cdev; if (!p) { struct kobject *kobj; - int idx, ret; - dev_t rdev = inode->i_rdev; + int idx; + dev_t mdev = inode->i_rdev; spin_unlock(&cdev_lock); - ret = vs_map_device(current->vx_info, &rdev); - if (ret) - return ret; + if (!vs_map_chrdev(&mdev, DATTR_OPEN)) + return -EPERM; + inode->i_mdev = mdev; - kobj = kobj_lookup(cdev_map, rdev, &idx); + kobj = kobj_lookup(cdev_map, mdev, &idx); if (!kobj) return -ENXIO; new = container_of(kobj, struct cdev, kobj); diff -NurpP --minimal linux-2.6.19-vs2.1.1.5.1/fs/inode.c linux-2.6.19-vs2.1.1.5.2/fs/inode.c --- linux-2.6.19-vs2.1.1.5.1/fs/inode.c 2006-12-11 00:15:36 +0100 +++ linux-2.6.19-vs2.1.1.5.2/fs/inode.c 2006-12-11 22:54:18 +0100 @@ -139,6 +139,7 @@ static struct inode *alloc_inode(struct inode->i_bdev = NULL; inode->i_cdev = NULL; inode->i_rdev = 0; + inode->i_mdev = 0; inode->dirtied_when = 0; if (security_inode_alloc(inode)) { if (inode->i_sb->s_op->destroy_inode) @@ -1428,9 +1429,11 @@ void init_special_inode(struct inode *in if (S_ISCHR(mode)) { inode->i_fop = &def_chr_fops; inode->i_rdev = rdev; + inode->i_mdev = rdev; } else if (S_ISBLK(mode)) { inode->i_fop = &def_blk_fops; inode->i_rdev = rdev; + inode->i_mdev = rdev; } else if (S_ISFIFO(mode)) inode->i_fop = &def_fifo_fops; else if (S_ISSOCK(mode)) diff -NurpP --minimal linux-2.6.19-vs2.1.1.5.1/include/linux/fs.h linux-2.6.19-vs2.1.1.5.2/include/linux/fs.h --- linux-2.6.19-vs2.1.1.5.1/include/linux/fs.h 2006-11-08 19:20:31 +0100 +++ linux-2.6.19-vs2.1.1.5.2/include/linux/fs.h 2006-12-11 22:54:37 +0100 @@ -576,6 +576,7 @@ struct inode { gid_t i_gid; tag_t i_tag; dev_t i_rdev; + dev_t i_mdev; loff_t i_size; struct timespec i_atime; struct timespec i_mtime; @@ -712,12 +713,12 @@ static inline void i_size_write(struct i static inline unsigned iminor(struct inode *inode) { - return MINOR(inode->i_rdev); + return MINOR(inode->i_mdev); } static inline unsigned imajor(struct inode *inode) { - return MAJOR(inode->i_rdev); + return MAJOR(inode->i_mdev); } extern struct block_device *I_BDEV(struct inode *inode); diff -NurpP --minimal linux-2.6.19-vs2.1.1.5.1/include/linux/vs_device.h linux-2.6.19-vs2.1.1.5.2/include/linux/vs_device.h --- linux-2.6.19-vs2.1.1.5.1/include/linux/vs_device.h 1970-01-01 01:00:00 +0100 +++ linux-2.6.19-vs2.1.1.5.2/include/linux/vs_device.h 2006-12-11 23:58:22 +0100 @@ -0,0 +1,26 @@ +#ifndef _VS_DEVICE_H +#define _VS_DEVICE_H + +#include "vserver/base.h" +#include "vserver/device.h" +#include "vserver/debug.h" + + +int vs_map_device(struct vx_info *, dev_t *, umode_t); + +#define vs_map_chrdev(d,p) \ + ((vs_map_device(current_vx_info(), d, S_IFCHR) & (p)) == (p)) +#define vs_map_blkdev(d,p) \ + ((vs_map_device(current_vx_info(), d, S_IFBLK) & (p)) == (p)) + +int vs_device_permission(struct vx_info *, dev_t, umode_t, int); + +#define vs_chrdev_permission(d,p) \ + vs_device_permission(current_vx_info(), d, S_IFCHR, p) +#define vs_blkdev_permission(d,p) \ + vs_device_permission(current_vx_info(), d, S_IFBLK, p) + + +#else +#warning duplicate inclusion +#endif diff -NurpP --minimal linux-2.6.19-vs2.1.1.5.1/include/linux/vserver/device.h linux-2.6.19-vs2.1.1.5.2/include/linux/vserver/device.h --- linux-2.6.19-vs2.1.1.5.1/include/linux/vserver/device.h 2006-12-11 00:35:54 +0100 +++ linux-2.6.19-vs2.1.1.5.2/include/linux/vserver/device.h 2006-12-11 23:06:48 +0100 @@ -7,11 +7,8 @@ #define DATTR_REMAP 0x00000010 -#define DATTR_CHR 0x00000100 -#define DATTR_BLK 0x00000200 - +#define DATTR_MASK 0x00000013 -int vs_map_device(struct vx_info *, dev_t *); #else /* _VX_DEVICE_H */ #warning duplicate inclusion diff -NurpP --minimal linux-2.6.19-vs2.1.1.5.1/kernel/vserver/device.c linux-2.6.19-vs2.1.1.5.2/kernel/vserver/device.c --- linux-2.6.19-vs2.1.1.5.1/kernel/vserver/device.c 2006-12-11 02:04:39 +0100 +++ linux-2.6.19-vs2.1.1.5.2/kernel/vserver/device.c 2006-12-11 23:57:10 +0100 @@ -21,6 +21,7 @@ #include #include #include +#include #include @@ -97,7 +98,7 @@ static inline void __unhash_mapping(stru static inline int __lookup_mapping(struct vx_info *vxi, - dev_t device, dev_t *target, int *flags) + dev_t device, dev_t *target, int *flags, umode_t mode) { spinlock_t *hash_lock = &dmap_main_hash_lock; struct hlist_head *hash = dmap_main_hash; @@ -110,10 +111,15 @@ static inline int __lookup_mapping(struc hlist_for_each(pos, head) { vdm = hlist_entry(pos, struct vs_mapping, dm_hlist); - if (vdm->device == device) + if ((vdm->device == device) && + !((vdm->flags ^ mode) & S_IFMT)) goto found; } ret = 0; + if (target) + *target = device; + if (flags) + *flags = DATTR_OPEN|DATTR_CREATE; goto out; found: if (target) @@ -128,24 +134,44 @@ out: - -int vs_map_device(struct vx_info *vxi, dev_t *device) +int vs_map_device(struct vx_info *vxi, dev_t *device, umode_t mode) { dev_t target = ~0; int ret, flags = 0; - ret = __lookup_mapping(vxi, *device, &target, &flags); - if (!ret) - target = *device; - printk("··· mapping device: %08x target: %08x flags: %04x ret=%d\n", *device, target, flags, ret); + if (!vxi && 0) + return DATTR_MASK; + + ret = __lookup_mapping(vxi, *device, &target, &flags, mode); + printk("··· mapping device: %08x target: %08x flags: %04x mode: %04x mapped=%d\n", + *device, target, flags, mode, ret); *device = target; - return 0; + return (flags & DATTR_MASK); } +int vs_device_permission(struct vx_info *vxi, + dev_t device, umode_t mode, int perm) +{ + int ret, flags = 0; + + if (!vxi && 0) + return -1; -int do_set_mapping(struct vx_info *vxi, dev_t device, dev_t target, int flags) + ret = __lookup_mapping(vxi, device, NULL, &flags, mode); + printk("··· device perm: %08x flags/perm: %04x/%04x mode: %04x mapped=%d\n", + device, flags, perm, mode, ret); + + if ((flags & perm) != perm) + return 0; + return flags; +} + + + +int do_set_mapping(struct vx_info *vxi, + dev_t device, dev_t target, int flags, umode_t mode) { struct vs_mapping *new; @@ -156,7 +182,7 @@ int do_set_mapping(struct vx_info *vxi, INIT_HLIST_NODE(&new->dm_hlist); new->device = device; new->target = target; - new->flags = flags; + new->flags = flags | mode; printk("··· device: %08x target: %08x\n", device, target); __hash_mapping(vxi, new); @@ -165,7 +191,7 @@ int do_set_mapping(struct vx_info *vxi, static inline -int __user_device(const char __user *name, dev_t *dev) +int __user_device(const char __user *name, dev_t *dev, umode_t *mode) { struct nameidata nd; int ret; @@ -177,29 +203,56 @@ int __user_device(const char __user *nam ret = user_path_walk_link(name, &nd); if (ret) return ret; - if (nd.dentry->d_inode) + if (nd.dentry->d_inode) { *dev = nd.dentry->d_inode->i_rdev; + *mode = nd.dentry->d_inode->i_mode; + } path_release(&nd); return 0; } +static inline +int __mapping_mode(dev_t device, dev_t target, + umode_t device_mode, umode_t target_mode, umode_t *mode) +{ + if (device) + *mode = device_mode & S_IFMT; + else if (target) + *mode = target_mode & S_IFMT; + else + *mode = 0; + + /* if both given, device and target mode have to match */ + if (device && target && + ((device_mode ^ target_mode) & S_IFMT)) + return -EINVAL; + return 0; +} + + int vc_set_mapping(struct vx_info *vxi, void __user *data) { struct vcmd_set_mapping_v0 vc_data; dev_t device = ~0, target = ~0; + umode_t device_mode, target_mode, mode; int ret; if (copy_from_user (&vc_data, data, sizeof(vc_data))) return -EFAULT; - ret = __user_device(vc_data.device, &device); + ret = __user_device(vc_data.device, &device, &device_mode); if (ret) return ret; - ret = __user_device(vc_data.target, &target); + ret = __user_device(vc_data.target, &target, &target_mode); if (ret) return ret; - return do_set_mapping(vxi, device, target, vc_data.flags); + ret = __mapping_mode(device, target, + device_mode, target_mode, &mode); + if (ret) + return ret; + + return do_set_mapping(vxi, device, target, vc_data.flags, mode); } #ifdef CONFIG_COMPAT @@ -220,7 +273,12 @@ int vc_set_mapping_x32(struct vx_info *v if (ret) return ret; - return do_set_mapping(vxi, device, target, vc_data.flags); + ret = __mapping_mode(device, target, + device_mode, target_mode, &mode); + if (ret) + return ret; + + return do_set_mapping(vxi, device, target, vc_data.flags, mode); } #endif /* CONFIG_COMPAT */