--- linux-2.6.11-rc1/fs/namespace.c 2004-12-25 01:55:21 +0100 +++ linux-2.6.11-rc1-vs1.9.4-rc2/fs/namespace.c 2005-01-15 11:27:52 +0100 @@ -161,6 +164,7 @@ clone_mnt(struct vfsmount *old, struct d mnt->mnt_mountpoint = mnt->mnt_root; mnt->mnt_parent = mnt; mnt->mnt_namespace = old->mnt_namespace; + mnt->mnt_xid = old->mnt_xid; /* stick the duplicate mount on the same expiry list * as the original if that was on one */ --- linux-2.6.11-rc1/fs/namespace.c 2004-12-25 01:55:21 +0100 +++ linux-2.6.11-rc1-vs1.9.4-rc2/fs/namespace.c 2005-01-15 11:27:52 +0100 @@ -238,6 +243,11 @@ static int show_vfsmnt(struct seq_file * }; struct proc_fs_info *fs_infop; + if (vx_flags(VXF_HIDE_MOUNT, 0)) + return 0; + if (!vx_check_vfsmount(current->vx_info, mnt)) + return 0; + mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none"); seq_putc(m, ' '); seq_path(m, mnt, mnt->mnt_root, " \t\n\\"); --- linux-2.6.11-rc1/fs/namespace.c 2004-12-25 01:55:21 +0100 +++ linux-2.6.11-rc1-vs1.9.4-rc2/fs/namespace.c 2005-01-15 11:27:52 +0100 @@ -252,6 +262,8 @@ static int show_vfsmnt(struct seq_file * if (mnt->mnt_flags & fs_infop->flag) seq_puts(m, fs_infop->str); } + if (mnt->mnt_flags & MNT_XID) + seq_printf(m, ",xid=%d", mnt->mnt_xid); if (mnt->mnt_sb->s_op->show_options) err = mnt->mnt_sb->s_op->show_options(m, mnt); seq_puts(m, " 0 0\n"); --- linux-2.6.11-rc1/fs/namespace.c 2004-12-25 01:55:21 +0100 +++ linux-2.6.11-rc1-vs1.9.4-rc2/fs/namespace.c 2005-01-15 11:27:52 +0100 @@ -337,18 +349,12 @@ int may_umount(struct vfsmount *mnt) EXPORT_SYMBOL(may_umount); -void umount_tree(struct vfsmount *mnt) +static inline void __umount_list(struct list_head *kill) { - struct vfsmount *p; - LIST_HEAD(kill); - - for (p = mnt; p; p = next_mnt(p, mnt)) { - list_del(&p->mnt_list); - list_add(&p->mnt_list, &kill); - } + struct vfsmount *mnt; - while (!list_empty(&kill)) { - mnt = list_entry(kill.next, struct vfsmount, mnt_list); + while (!list_empty(kill)) { + mnt = list_entry(kill->next, struct vfsmount, mnt_list); list_del_init(&mnt->mnt_list); list_del_init(&mnt->mnt_fslink); if (mnt->mnt_parent == mnt) { --- linux-2.6.11-rc1/fs/namespace.c 2004-12-25 01:55:21 +0100 +++ linux-2.6.11-rc1-vs1.9.4-rc2/fs/namespace.c 2005-01-15 11:27:52 +0100 @@ -364,6 +370,32 @@ void umount_tree(struct vfsmount *mnt) } } +void umount_tree(struct vfsmount *mnt) +{ + struct vfsmount *p; + LIST_HEAD(kill); + + for (p = mnt; p; p = next_mnt(p, mnt)) { + list_del(&p->mnt_list); + list_add(&p->mnt_list, &kill); + } + __umount_list(&kill); +} + +void umount_unused(struct vfsmount *mnt, struct fs_struct *fs) +{ + struct vfsmount *p; + LIST_HEAD(kill); + + for (p = mnt; p; p = next_mnt(p, mnt)) { + if (p == fs->rootmnt || p == fs->pwdmnt) + continue; + list_del(&p->mnt_list); + list_add(&p->mnt_list, &kill); + } + __umount_list(&kill); +} + static int do_umount(struct vfsmount *mnt, int flags) { struct super_block * sb = mnt->mnt_sb; --- linux-2.6.11-rc1/fs/namespace.c 2004-12-25 01:55:21 +0100 +++ linux-2.6.11-rc1-vs1.9.4-rc2/fs/namespace.c 2005-01-15 11:27:52 +0100 @@ -480,7 +512,7 @@ asmlinkage long sys_umount(char __user * goto dput_and_out; retval = -EPERM; - if (!capable(CAP_SYS_ADMIN)) + if (!capable(CAP_SYS_ADMIN) && !vx_ccaps(VXC_SECURE_MOUNT)) goto dput_and_out; retval = do_umount(nd.mnt, flags); --- linux-2.6.11-rc1/fs/namespace.c 2004-12-25 01:55:21 +0100 +++ linux-2.6.11-rc1-vs1.9.4-rc2/fs/namespace.c 2005-01-15 11:27:52 +0100 @@ -507,6 +539,8 @@ static int mount_is_safe(struct nameidat { if (capable(CAP_SYS_ADMIN)) return 0; + if (vx_ccaps(VXC_SECURE_MOUNT)) + return 0; return -EPERM; #ifdef notyet if (S_ISLNK(nd->dentry->d_inode->i_mode)) --- linux-2.6.11-rc1/fs/namespace.c 2004-12-25 01:55:21 +0100 +++ linux-2.6.11-rc1-vs1.9.4-rc2/fs/namespace.c 2005-01-15 11:27:52 +0100 @@ -618,11 +652,12 @@ out_unlock: /* * do loopback mount. */ -static int do_loopback(struct nameidata *nd, char *old_name, int recurse) +static int do_loopback(struct nameidata *nd, char *old_name, xid_t xid, int flags) { struct nameidata old_nd; struct vfsmount *mnt = NULL; int err = mount_is_safe(nd); + int recurse = flags & MS_REC; if (err) return err; if (!old_name || !*old_name) --- linux-2.6.11-rc1/fs/namespace.c 2004-12-25 01:55:21 +0100 +++ linux-2.6.11-rc1-vs1.9.4-rc2/fs/namespace.c 2005-01-15 11:27:52 +0100 @@ -647,6 +682,10 @@ static int do_loopback(struct nameidata list_del_init(&mnt->mnt_fslink); spin_unlock(&vfsmount_lock); + if (flags & MS_XID) { + mnt->mnt_xid = xid; + mnt->mnt_flags |= MNT_XID; + } err = graft_tree(mnt, nd); if (err) { spin_lock(&vfsmount_lock); --- linux-2.6.11-rc1/fs/namespace.c 2004-12-25 01:55:21 +0100 +++ linux-2.6.11-rc1-vs1.9.4-rc2/fs/namespace.c 2005-01-15 11:27:52 +0100 @@ -668,12 +707,12 @@ static int do_loopback(struct nameidata */ static int do_remount(struct nameidata *nd, int flags, int mnt_flags, - void *data) + void *data, xid_t xid) { int err; struct super_block * sb = nd->mnt->mnt_sb; - if (!capable(CAP_SYS_ADMIN)) + if (!capable(CAP_SYS_ADMIN) && !vx_ccaps(VXC_SECURE_REMOUNT)) return -EPERM; if (!check_mnt(nd->mnt)) --- linux-2.6.11-rc1/fs/namespace.c 2004-12-25 01:55:21 +0100 +++ linux-2.6.11-rc1-vs1.9.4-rc2/fs/namespace.c 2005-01-15 11:27:52 +0100 @@ -682,10 +721,15 @@ static int do_remount(struct nameidata * if (nd->dentry != nd->mnt->mnt_root) return -EINVAL; + if (vx_ccaps(VXC_SECURE_REMOUNT)) + mnt_flags |= MNT_NODEV; down_write(&sb->s_umount); err = do_remount_sb(sb, flags, data, 0); - if (!err) + if (!err) { nd->mnt->mnt_flags=mnt_flags; + if (flags & MS_XID) + nd->mnt->mnt_xid = xid; + } up_write(&sb->s_umount); if (!err) security_sb_post_remount(nd->mnt, flags, data); --- linux-2.6.11-rc1/fs/namespace.c 2004-12-25 01:55:21 +0100 +++ linux-2.6.11-rc1-vs1.9.4-rc2/fs/namespace.c 2005-01-15 11:27:52 +0100 @@ -697,7 +741,7 @@ static int do_move_mount(struct nameidat struct nameidata old_nd, parent_nd; struct vfsmount *p; int err = 0; - if (!capable(CAP_SYS_ADMIN)) + if (!capable(CAP_SYS_ADMIN) && !vx_ccaps(VXC_SECURE_MOUNT)) return -EPERM; if (!old_name || !*old_name) return -EINVAL; --- linux-2.6.11-rc1/fs/namespace.c 2004-12-25 01:55:21 +0100 +++ linux-2.6.11-rc1-vs1.9.4-rc2/fs/namespace.c 2005-01-15 11:27:52 +0100 @@ -769,7 +813,7 @@ static int do_new_mount(struct nameidata return -EINVAL; /* we need capabilities... */ - if (!capable(CAP_SYS_ADMIN)) + if (!capable(CAP_SYS_ADMIN) && !vx_ccaps(VXC_SECURE_MOUNT)) return -EPERM; mnt = do_kern_mount(type, flags, name, data); --- linux-2.6.11-rc1/fs/namespace.c 2004-12-25 01:55:21 +0100 +++ linux-2.6.11-rc1-vs1.9.4-rc2/fs/namespace.c 2005-01-15 11:27:52 +0100 @@ -1011,6 +1055,7 @@ long do_mount(char * dev_name, char * di struct nameidata nd; int retval = 0; int mnt_flags = 0; + xid_t xid = 0; /* Discard magic */ if ((flags & MS_MGC_MSK) == MS_MGC_VAL) --- linux-2.6.11-rc1/fs/namespace.c 2004-12-25 01:55:21 +0100 +++ linux-2.6.11-rc1-vs1.9.4-rc2/fs/namespace.c 2005-01-15 11:27:52 +0100 @@ -1026,6 +1071,14 @@ long do_mount(char * dev_name, char * di if (data_page) ((char *)data_page)[PAGE_SIZE - 1] = 0; + retval = vx_parse_xid(data_page, &xid, 1); + if (retval) { + mnt_flags |= MNT_XID; + /* bind and re-mounts get xid flag */ + if (flags & (MS_BIND|MS_REMOUNT)) + flags |= MS_XID; + } + /* Separate the per-mountpoint flags */ if (flags & MS_NOSUID) mnt_flags |= MNT_NOSUID; --- linux-2.6.11-rc1/fs/namespace.c 2004-12-25 01:55:21 +0100 +++ linux-2.6.11-rc1-vs1.9.4-rc2/fs/namespace.c 2005-01-15 11:27:52 +0100 @@ -1035,6 +1088,9 @@ long do_mount(char * dev_name, char * di mnt_flags |= MNT_NOEXEC; flags &= ~(MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_ACTIVE); + if (vx_ccaps(VXC_SECURE_MOUNT)) + mnt_flags |= MNT_NODEV; + /* ... and get the mountpoint */ retval = path_lookup(dir_name, LOOKUP_FOLLOW, &nd); if (retval) --- linux-2.6.11-rc1/fs/namespace.c 2004-12-25 01:55:21 +0100 +++ linux-2.6.11-rc1-vs1.9.4-rc2/fs/namespace.c 2005-01-15 11:27:52 +0100 @@ -1046,9 +1102,9 @@ long do_mount(char * dev_name, char * di if (flags & MS_REMOUNT) retval = do_remount(&nd, flags & ~MS_REMOUNT, mnt_flags, - data_page); + data_page, xid); else if (flags & MS_BIND) - retval = do_loopback(&nd, dev_name, flags & MS_REC); + retval = do_loopback(&nd, dev_name, xid, flags); else if (flags & MS_MOVE) retval = do_move_mount(&nd, dev_name); else --- linux-2.6.11-rc1/fs/namespace.c 2004-12-25 01:55:21 +0100 +++ linux-2.6.11-rc1-vs1.9.4-rc2/fs/namespace.c 2005-01-15 11:27:52 +0100 @@ -1075,7 +1131,7 @@ int copy_namespace(int flags, struct tas if (!(flags & CLONE_NEWNS)) return 0; - if (!capable(CAP_SYS_ADMIN)) { + if (!capable(CAP_SYS_ADMIN) && !vx_ccaps(VXC_SECURE_MOUNT)) { put_namespace(namespace); return -EPERM; } --- linux-2.6.11-rc1/include/linux/namespace.h 2004-08-14 12:55:33 +0200 +++ linux-2.6.11-rc1-vs1.9.4-rc2/include/linux/namespace.h 2005-01-15 11:27:52 +0100 @@ -13,6 +13,7 @@ struct namespace { }; extern void umount_tree(struct vfsmount *); +extern void umount_unused(struct vfsmount *, struct fs_struct *); extern int copy_namespace(int, struct task_struct *); extern void __put_namespace(struct namespace *namespace); --- linux-2.6.11-rc1/include/linux/vserver/namespace.h 1970-01-01 01:00:00 +0100 +++ linux-2.6.11-rc1-vs1.9.4-rc2/include/linux/vserver/namespace.h 2005-01-15 11:27:52 +0100 @@ -0,0 +1,60 @@ +#ifndef _VX_NAMESPACE_H +#define _VX_NAMESPACE_H + +#include + + +/* virtual host info names */ + +#define VCMD_vx_set_vhi_name VC_CMD(VHOST, 1, 0) +#define VCMD_vx_get_vhi_name VC_CMD(VHOST, 2, 0) + +struct vcmd_vx_vhi_name_v0 { + uint32_t field; + char name[65]; +}; + + +enum vx_vhi_name_field { + VHIN_CONTEXT=0, + VHIN_SYSNAME, + VHIN_NODENAME, + VHIN_RELEASE, + VHIN_VERSION, + VHIN_MACHINE, + VHIN_DOMAINNAME, +}; + + +#ifdef __KERNEL__ + +#include + +extern int vc_set_vhi_name(uint32_t, void __user *); +extern int vc_get_vhi_name(uint32_t, void __user *); + +#endif /* __KERNEL__ */ + +#define VCMD_enter_namespace VC_CMD(PROCALT, 1, 0) +#define VCMD_cleanup_namespace VC_CMD(PROCALT, 2, 0) +#define VCMD_set_namespace VC_CMD(PROCALT, 3, 0) + +#ifdef __KERNEL__ + +struct vx_info; +struct namespace; +struct fs_struct; +struct vfsmount; + +extern int vx_check_vfsmount(struct vx_info *, struct vfsmount *); + +extern int vx_set_namespace(struct vx_info *, struct namespace *, struct fs_struct *); + +extern int vc_enter_namespace(uint32_t, void __user *); +extern int vc_cleanup_namespace(uint32_t, void __user *); +extern int vc_set_namespace(uint32_t, void __user *); + +#endif /* __KERNEL__ */ +#else /* _VX_NAMESPACE_H */ +#warning duplicate inclusion +#endif /* _VX_NAMESPACE_H */ --- linux-2.6.11-rc1/kernel/vserver/namespace.c 1970-01-01 01:00:00 +0100 +++ linux-2.6.11-rc1-vs1.9.4-rc2/kernel/vserver/namespace.c 2005-01-15 11:27:52 +0100 @@ -0,0 +1,240 @@ +/* + * linux/kernel/vserver/namespace.c + * + * Virtual Server: Context Namespace Support + * + * Copyright (C) 2003-2004 Herbert Pötzl + * + * V0.01 broken out from context.c 0.07 + * V0.02 added task locking for namespace + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +int vx_check_vfsmount(struct vx_info *vxi, struct vfsmount *mnt) +{ + struct vfsmount *root_mnt, *altroot_mnt; + struct dentry *root, *altroot, *point; + int r1, r2, s1, s2, ret = 0; + + if (!vxi || !mnt) + return 1; + + spin_lock(&dcache_lock); + altroot_mnt = current->fs->rootmnt; + altroot = current->fs->root; + point = altroot; + + if (vxi->vx_fs) { + root_mnt = vxi->vx_fs->rootmnt; + root = vxi->vx_fs->root; + } else { + root_mnt = altroot_mnt; + root = altroot; + } + /* printk("ˇˇˇ %p:%p/%p:%p ", + root_mnt, root, altroot_mnt, altroot); */ + + while ((mnt != mnt->mnt_parent) && + (mnt != root_mnt) && (mnt != altroot_mnt)) { + point = mnt->mnt_mountpoint; + mnt = mnt->mnt_parent; + } + + r1 = (mnt == root_mnt); + s1 = is_subdir(point, root); + r2 = (mnt == altroot_mnt); + s2 = is_subdir(point, altroot); + + ret = (((mnt == root_mnt) && is_subdir(point, root)) || + ((mnt == altroot_mnt) && is_subdir(point, altroot))); + /* printk("ˇˇˇ for %p:%p -> %d:%d/%d:%d = %d\n", + mnt, point, r1, s1, r2, s2, ret); */ + spin_unlock(&dcache_lock); + + return (r2 && s2); +} + + +/* virtual host info names */ + +static char * vx_vhi_name(struct vx_info *vxi, int id) +{ + switch (id) { + case VHIN_CONTEXT: + return vxi->vx_name; + case VHIN_SYSNAME: + return vxi->cvirt.utsname.sysname; + case VHIN_NODENAME: + return vxi->cvirt.utsname.nodename; + case VHIN_RELEASE: + return vxi->cvirt.utsname.release; + case VHIN_VERSION: + return vxi->cvirt.utsname.version; + case VHIN_MACHINE: + return vxi->cvirt.utsname.machine; + case VHIN_DOMAINNAME: + return vxi->cvirt.utsname.domainname; + default: + return NULL; + } + return NULL; +} + +int vc_set_vhi_name(uint32_t id, void __user *data) +{ + struct vx_info *vxi; + struct vcmd_vx_vhi_name_v0 vc_data; + char *name; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (copy_from_user (&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + vxi = locate_vx_info(id); + if (!vxi) + return -ESRCH; + + name = vx_vhi_name(vxi, vc_data.field); + if (name) + memcpy(name, vc_data.name, 65); + put_vx_info(vxi); + return (name ? 0 : -EFAULT); +} + +int vc_get_vhi_name(uint32_t id, void __user *data) +{ + struct vx_info *vxi; + struct vcmd_vx_vhi_name_v0 vc_data; + char *name; + + if (copy_from_user (&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + vxi = locate_vx_info(id); + if (!vxi) + return -ESRCH; + + name = vx_vhi_name(vxi, vc_data.field); + if (!name) + goto out_put; + + memcpy(vc_data.name, name, 65); + if (copy_to_user (data, &vc_data, sizeof(vc_data))) + return -EFAULT; +out_put: + put_vx_info(vxi); + return (name ? 0 : -EFAULT); +} + +/* namespace functions */ + +#include + +int vx_set_namespace(struct vx_info *vxi, struct namespace *ns, struct fs_struct *fs) +{ + struct fs_struct *fs_copy; + + if (vxi->vx_namespace) + return -EPERM; + if (!ns || !fs) + return -EINVAL; + + fs_copy = copy_fs_struct(fs); + if (!fs_copy) + return -ENOMEM; + + get_namespace(ns); + vxi->vx_namespace = ns; + vxi->vx_fs = fs_copy; + return 0; +} + +int vc_enter_namespace(uint32_t id, void *data) +{ + struct vx_info *vxi; + struct fs_struct *old_fs, *fs; + struct namespace *old_ns; + int ret = 0; + + if (!vx_check(0, VX_ADMIN)) + return -ENOSYS; + + vxi = locate_vx_info(id); + if (!vxi) + return -ESRCH; + + ret = -EINVAL; + if (!vxi->vx_namespace) + goto out_put; + + ret = -ENOMEM; + fs = copy_fs_struct(vxi->vx_fs); + if (!fs) + goto out_put; + + ret = 0; + task_lock(current); + old_ns = current->namespace; + old_fs = current->fs; + get_namespace(vxi->vx_namespace); + current->namespace = vxi->vx_namespace; + current->fs = fs; + task_unlock(current); + + put_namespace(old_ns); + put_fs_struct(old_fs); +out_put: + put_vx_info(vxi); + return ret; +} + +int vc_cleanup_namespace(uint32_t id, void *data) +{ + down_write(¤t->namespace->sem); + spin_lock(&vfsmount_lock); + umount_unused(current->namespace->root, current->fs); + spin_unlock(&vfsmount_lock); + up_write(¤t->namespace->sem); + return 0; +} + +int vc_set_namespace(uint32_t id, void __user *data) +{ + struct fs_struct *fs; + struct namespace *ns; + struct vx_info *vxi; + int ret; + + if (vx_check(0, VX_ADMIN|VX_WATCH)) + return -ENOSYS; + + task_lock(current); + vxi = get_vx_info(current->vx_info); + fs = current->fs; + atomic_inc(&fs->count); + ns = current->namespace; + get_namespace(current->namespace); + task_unlock(current); + + ret = vx_set_namespace(vxi, ns, fs); + + put_namespace(ns); + put_fs_struct(fs); + put_vx_info(vxi); + return ret; +} +