diff -Nurp linux-2.6.22-690/fs/attr.c linux-2.6.22-700/fs/attr.c --- linux-2.6.22-690/fs/attr.c 2009-01-08 18:12:22.000000000 +0100 +++ linux-2.6.22-700/fs/attr.c 2009-01-08 18:59:11.000000000 +0100 @@ -17,6 +17,7 @@ #include #include #include +#include /* Taken over from the old code... */ @@ -59,26 +60,9 @@ int inode_change_ok(struct inode *inode, goto error; } - /* Check for evil vserver activity */ - if (vx_check(0, VS_ADMIN)) - goto fine; - - if (IS_BARRIER(inode)) { - vxwprintk_task(1, "messing with the barrier."); + if (dx_permission(inode, MAY_WRITE)) goto error; - } - switch (inode->i_sb->s_magic) { - case PROC_SUPER_MAGIC: - /* maybe allow that in the future? */ - vxwprintk_task(1, "messing with the procfs."); - goto error; - case DEVPTS_SUPER_MAGIC: - /* devpts is xid tagged */ - if (vx_check((xid_t)inode->i_tag, VS_IDENT)) - goto fine; - vxwprintk_task(1, "messing with the devpts."); - goto error; - } + fine: retval = 0; error: diff -Nurp linux-2.6.22-690/fs/namei.c linux-2.6.22-700/fs/namei.c --- linux-2.6.22-690/fs/namei.c 2009-01-08 18:12:22.000000000 +0100 +++ linux-2.6.22-700/fs/namei.c 2009-01-08 18:33:41.000000000 +0100 @@ -233,26 +233,74 @@ int generic_permission(struct inode *ino static inline int dx_barrier(struct inode *inode) { - if (IS_BARRIER(inode) && !vx_check(0, VS_ADMIN)) { + if (IS_BARRIER(inode) && !vx_check(0, VS_ADMIN | VS_WATCH)) { vxwprintk_task(1, "did hit the barrier."); return 1; } return 0; } -static inline int dx_permission(struct inode *inode, int mask, struct nameidata *nd) +static inline int __dx_permission(struct inode *inode, int mask) { if (dx_barrier(inode)) return -EACCES; - if (dx_notagcheck(nd) || - dx_check(inode->i_tag, DX_HOSTID|DX_ADMIN|DX_WATCH|DX_IDENT)) - return 0; - vxwprintk_task(1, "denied access to %p[#%d,%lu] »%s«.", - inode, inode->i_tag, inode->i_ino, vxd_cond_path(nd)); + if (inode->i_sb->s_magic == DEVPTS_SUPER_MAGIC) { + /* devpts is xid tagged */ + if (S_ISDIR(inode->i_mode) || + vx_check((xid_t)inode->i_tag, VS_IDENT | VS_WATCH_P)) + return 0; + } + else if (inode->i_sb->s_magic == PROC_SUPER_MAGIC) { + struct proc_dir_entry *de = PDE(inode); + + if (de && !vx_hide_check(0, de->vx_flags)) + goto out; + + if ((mask & (MAY_WRITE | MAY_APPEND))) { + struct pid *pid; + struct task_struct *tsk; + + if (vx_check(0, VS_ADMIN | VS_WATCH_P) || + vx_flags(VXF_STATE_SETUP, 0) || + vx_capable(CAP_SYS_ADMIN, VXC_PROC_WRITE)) + return 0; + + pid = PROC_I(inode)->pid; + if (!pid) + goto out; + + tsk = pid_task(pid, PIDTYPE_PID); + vxdprintk(VXD_CBIT(tag, 0), "accessing %p[#%u]", + tsk, (tsk ? vx_task_xid(tsk) : 0)); + if (tsk && vx_check(vx_task_xid(tsk), VS_IDENT | VS_WATCH_P)) + return 0; + } + else + return 0; + } + else { + if (dx_notagcheck(inode->i_sb) || + dx_check(inode->i_tag, DX_HOSTID | DX_ADMIN | DX_WATCH | + DX_IDENT)) + return 0; + } + +out: return -EACCES; } +int dx_permission(struct inode *inode, int mask) +{ + int ret = __dx_permission(inode, mask); + if (unlikely(ret)) { + vxwprintk_task(1, "denied %x access to %s:%p[#%d,%lu]", + mask, inode->i_sb->s_id, inode, inode->i_tag, + inode->i_ino); + } + return ret; +} + int permission(struct inode *inode, int mask, struct nameidata *nd) { umode_t mode = inode->i_mode; @@ -284,14 +332,13 @@ int permission(struct inode *inode, int (nd && nd->mnt && (nd->mnt->mnt_flags & MNT_NOEXEC)))) return -EACCES; + retval = dx_permission(inode, mask); + if (retval) + return retval; + /* Ordinary permission routines do not understand MAY_APPEND. */ submask = mask & ~MAY_APPEND; - if ((inode->i_sb->s_magic != DEVPTS_SUPER_MAGIC) && - (inode->i_sb->s_magic != PROC_SUPER_MAGIC) && - (retval = dx_permission(inode, mask, nd))) - return retval; - if (inode->i_op && inode->i_op->permission) retval = inode->i_op->permission(inode, submask, nd); else @@ -817,27 +864,18 @@ static int do_lookup(struct nameidata *n if (!inode) goto done; - if (inode->i_sb->s_magic == PROC_SUPER_MAGIC) { - struct proc_dir_entry *de = PDE(inode); + if (__dx_permission(inode, MAY_ACCESS)) + goto hidden; - if (de && !vx_hide_check(0, de->vx_flags)) - goto hidden; - } else if (inode->i_sb->s_magic == DEVPTS_SUPER_MAGIC) { - if (!vx_check((xid_t)inode->i_tag, VS_WATCH_P | VS_IDENT)) - goto hidden; - } else { - if (!dx_notagcheck(nd) && !dx_check(inode->i_tag, - DX_WATCH | DX_ADMIN | DX_HOSTID | DX_IDENT)) - goto hidden; - } done: path->mnt = mnt; path->dentry = dentry; __follow_mount(path); return 0; hidden: - vxwprintk_task(1, "did lookup hidden %p[#%d,%lu] »%s«.", - inode, inode->i_tag, inode->i_ino, vxd_path(dentry, mnt)); + vxwprintk_task(1, "did lookup hidden %s:%p[#%d,%lu] »%s«.", + inode->i_sb->s_id, inode, inode->i_tag, inode->i_ino, + vxd_path(dentry, mnt)); dput(dentry); return -ENOENT; diff -Nurp linux-2.6.22-690/fs/namespace.c linux-2.6.22-700/fs/namespace.c --- linux-2.6.22-690/fs/namespace.c 2009-01-08 18:12:22.000000000 +0100 +++ linux-2.6.22-700/fs/namespace.c 2009-01-08 18:59:35.000000000 +0100 @@ -1470,9 +1470,7 @@ long do_mount(char *dev_name, char *dir_ if (data_page) ((char *)data_page)[PAGE_SIZE - 1] = 0; - retval = dx_parse_tag(data_page, &tag, 1); - if (retval) { - mnt_flags |= retval; + if (dx_parse_tag(data_page, &tag, 1, &mnt_flags, &flags)) { /* FIXME: bind and re-mounts get the tag flag? */ if (flags & (MS_BIND|MS_REMOUNT)) flags |= MS_TAGID; diff -Nurp linux-2.6.22-690/include/linux/fs.h linux-2.6.22-700/include/linux/fs.h --- linux-2.6.22-690/include/linux/fs.h 2009-01-08 18:12:34.000000000 +0100 +++ linux-2.6.22-700/include/linux/fs.h 2009-01-08 18:42:32.000000000 +0100 @@ -60,6 +60,7 @@ extern int dir_notify_enable; #define MAY_WRITE 2 #define MAY_READ 4 #define MAY_APPEND 8 +#define MAY_ACCESS 16 #define FMODE_READ 1 #define FMODE_WRITE 2 @@ -125,6 +126,7 @@ extern int dir_notify_enable; #define MS_RELATIME (1<<21) /* Update atime relative to mtime/ctime. */ #define MS_TAGGED (1<<24) /* use generic inode tagging */ #define MS_TAGID (1<<25) /* use specific tag for this mount */ +#define MS_NOTAGCHECK (1<<26) /* don't check tags */ #define MS_ACTIVE (1<<30) #define MS_NOUSER (1<<31) diff -Nurp linux-2.6.22-690/include/linux/mount.h linux-2.6.22-700/include/linux/mount.h --- linux-2.6.22-690/include/linux/mount.h 2009-01-08 18:12:23.000000000 +0100 +++ linux-2.6.22-700/include/linux/mount.h 2009-01-08 18:41:37.000000000 +0100 @@ -40,7 +40,6 @@ struct mnt_namespace; #define MNT_TAGID 0x10000 #define MNT_NOTAG 0x20000 -#define MNT_NOTAGCHECK 0x40000 struct vfsmount { struct list_head mnt_hash; diff -Nurp linux-2.6.22-690/include/linux/vserver/context.h linux-2.6.22-700/include/linux/vserver/context.h --- linux-2.6.22-690/include/linux/vserver/context.h 2009-01-08 18:12:24.000000000 +0100 +++ linux-2.6.22-700/include/linux/vserver/context.h 2009-01-08 18:49:20.000000000 +0100 @@ -73,6 +73,8 @@ #define VXC_KTHREAD 0x01000000 +#define VXC_PROC_WRITE 0x80000000ULL + #ifdef __KERNEL__ diff -Nurp linux-2.6.22-690/include/linux/vserver/tag.h linux-2.6.22-700/include/linux/vserver/tag.h --- linux-2.6.22-690/include/linux/vserver/tag.h 2009-01-08 18:12:24.000000000 +0100 +++ linux-2.6.22-700/include/linux/vserver/tag.h 2009-01-08 18:41:14.000000000 +0100 @@ -125,10 +125,11 @@ struct peer_tag { int32_t nid; }; -#define dx_notagcheck(nd) \ - ((nd) && (nd)->mnt && ((nd)->mnt->mnt_flags & MNT_NOTAGCHECK)) +#define dx_notagcheck(sb) \ + ((sb) && ((sb)->s_flags & MS_NOTAGCHECK)) -int dx_parse_tag(char *string, tag_t *tag, int remove); +int dx_parse_tag(char *string, tag_t *tag, int remove, int *mnt_flags, + unsigned long *flags); #ifdef CONFIG_PROPAGATE diff -Nurp linux-2.6.22-690/include/linux/vs_tag.h linux-2.6.22-700/include/linux/vs_tag.h --- linux-2.6.22-690/include/linux/vs_tag.h 2009-01-08 18:12:24.000000000 +0100 +++ linux-2.6.22-700/include/linux/vs_tag.h 2009-01-08 18:37:43.000000000 +0100 @@ -38,6 +38,9 @@ static inline int __dx_check(tag_t cid, ((mode & DX_HOSTID) && (id == 0))); } +struct inode; +int dx_permission(struct inode *inode, int mask); + #else #warning duplicate inclusion #endif diff -Nurp linux-2.6.22-690/kernel/vserver/inode.c linux-2.6.22-700/kernel/vserver/inode.c --- linux-2.6.22-690/kernel/vserver/inode.c 2009-01-08 18:12:31.000000000 +0100 +++ linux-2.6.22-700/kernel/vserver/inode.c 2009-01-08 19:16:55.000000000 +0100 @@ -325,56 +325,69 @@ static void __dx_parse_remove(char *stri } } -static inline -int __dx_parse_tag(char *string, tag_t *tag, int remove) +int dx_parse_tag(char *string, tag_t *tag, int remove, int *mnt_flags, + unsigned long *flags) { + int set = 0; substring_t args[MAX_OPT_ARGS]; int token, option = 0; + char *s, *p, *opts; if (!string) return 0; + s = kstrdup(string, GFP_KERNEL | GFP_ATOMIC); + if (!s) + return 0; - token = match_token(string, tokens, args); - - vxdprintk(VXD_CBIT(tag, 7), - "dx_parse_tag(»%s«): %d:#%d", - string, token, option); - - switch (token) { - case Opt_tag: - if (tag) - *tag = 0; - if (remove) - __dx_parse_remove(string, "tag"); - return MNT_TAGID; - case Opt_notag: - if (remove) - __dx_parse_remove(string, "notag"); - return MNT_NOTAG; - case Opt_notagcheck: - if (remove) - __dx_parse_remove(string, "notagcheck"); - return MNT_NOTAGCHECK; - case Opt_tagid: - if (tag && !match_int(args, &option)) - *tag = option; - if (remove) - __dx_parse_remove(string, "tagid"); - return MNT_TAGID; - } - return 0; -} - -int dx_parse_tag(char *string, tag_t *tag, int remove) -{ - int retval, flags = 0; #ifdef CONFIG_VSERVER_FILESHARING - flags |= MNT_NOTAGCHECK; + *flags |= MS_NOTAGCHECK; #endif - while ((retval = __dx_parse_tag(string, tag, remove))) - flags |= retval; - return flags; + opts = s; + while ((p = strsep(&opts, ",")) != NULL) { + token = match_token(p, tokens, args); + + vxdprintk(VXD_CBIT(tag, 7), + "dx_parse_tag(»%s«): %d:#%d", + p, token, option); + + switch (token) { +#ifdef CONFIG_PROPAGATE + case Opt_tag: + if (tag) + *tag = 0; + if (remove) + __dx_parse_remove(s, "tag"); + *mnt_flags |= MNT_TAGID; + set |= MNT_TAGID; + break; + case Opt_notag: + if (remove) + __dx_parse_remove(s, "notag"); + *mnt_flags |= MNT_NOTAG; + set |= MNT_NOTAG; + break; + case Opt_tagid: + if (tag && !match_int(args, &option)) + *tag = option; + if (remove) + __dx_parse_remove(s, "tagid"); + *mnt_flags |= MNT_TAGID; + set |= MNT_TAGID; + break; +#endif + case Opt_notagcheck: + if (remove) + __dx_parse_remove(s, "notagcheck"); + *flags |= MS_NOTAGCHECK; + set |= MS_NOTAGCHECK; + break; + } + } + if (set) + strcpy(string, s); + kfree(s); + return set; } #ifdef CONFIG_PROPAGATE