X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=fs%2Fattr.c;h=3317d4fe522014a6908d27211aeec8feda86501e;hb=f7f1b0f1e2fbadeab12d24236000e778aa9b1ead;hp=d63350cfcb3cb81766be7ac9c073cb3765b29ee7;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/fs/attr.c b/fs/attr.c index d63350cfc..3317d4fe5 100644 --- a/fs/attr.c +++ b/fs/attr.c @@ -14,6 +14,10 @@ #include #include #include +#include +#include +#include +#include /* Taken over from the old code... */ @@ -35,7 +39,8 @@ int inode_change_ok(struct inode *inode, struct iattr *attr) /* Make sure caller can chgrp. */ if ((ia_valid & ATTR_GID) && - (!in_group_p(attr->ia_gid) && attr->ia_gid != inode->i_gid) && + (current->fsuid != inode->i_uid || + (!in_group_p(attr->ia_gid) && attr->ia_gid != inode->i_gid)) && !capable(CAP_CHOWN)) goto error; @@ -54,6 +59,28 @@ int inode_change_ok(struct inode *inode, struct iattr *attr) if (current->fsuid != inode->i_uid && !capable(CAP_FOWNER)) goto error; } + + /* Check for evil vserver activity */ + if (vx_check(0, VX_ADMIN)) + goto fine; + + if (IS_BARRIER(inode)) { + vxwprintk(1, "xid=%d messing with the barrier.", + vx_current_xid()); + goto error; + } + switch (inode->i_sb->s_magic) { + case PROC_SUPER_MAGIC: + vxwprintk(1, "xid=%d messing with the procfs.", + vx_current_xid()); + goto error; + case DEVPTS_SUPER_MAGIC: + if (vx_check(inode->i_xid, VX_IDENT)) + goto fine; + vxwprintk(1, "xid=%d messing with the devpts.", + vx_current_xid()); + goto error; + } fine: retval = 0; error: @@ -62,6 +89,24 @@ error: EXPORT_SYMBOL(inode_change_ok); +int inode_setattr_flags(struct inode *inode, unsigned int flags) +{ + unsigned int oldflags, newflags; + + oldflags = inode->i_flags; + newflags = oldflags & ~(S_IMMUTABLE | S_IUNLINK | S_BARRIER); + if (flags & ATTR_FLAG_IMMUTABLE) + newflags |= S_IMMUTABLE; + if (flags & ATTR_FLAG_IUNLINK) + newflags |= S_IUNLINK; + if (flags & ATTR_FLAG_BARRIER) + newflags |= S_BARRIER; + + if (oldflags ^ newflags) + inode->i_flags = newflags; + return 0; +} + int inode_setattr(struct inode * inode, struct iattr * attr) { unsigned int ia_valid = attr->ia_valid; @@ -85,12 +130,17 @@ int inode_setattr(struct inode * inode, struct iattr * attr) inode->i_uid = attr->ia_uid; if (ia_valid & ATTR_GID) inode->i_gid = attr->ia_gid; + if (ia_valid & ATTR_XID) + inode->i_xid = attr->ia_xid; if (ia_valid & ATTR_ATIME) - inode->i_atime = attr->ia_atime; + inode->i_atime = timespec_trunc(attr->ia_atime, + inode->i_sb->s_time_gran); if (ia_valid & ATTR_MTIME) - inode->i_mtime = attr->ia_mtime; + inode->i_mtime = timespec_trunc(attr->ia_mtime, + inode->i_sb->s_time_gran); if (ia_valid & ATTR_CTIME) - inode->i_ctime = attr->ia_ctime; + inode->i_ctime = timespec_trunc(attr->ia_ctime, + inode->i_sb->s_time_gran); if (ia_valid & ATTR_MODE) { umode_t mode = attr->ia_mode; @@ -98,6 +148,8 @@ int inode_setattr(struct inode * inode, struct iattr * attr) mode &= ~S_ISGID; inode->i_mode = mode; } + if (ia_valid & ATTR_ATTR_FLAG) + inode_setattr_flags(inode, attr->ia_attr_flags); mark_inode_dirty(inode); out: return error; @@ -113,6 +165,8 @@ int setattr_mask(unsigned int ia_valid) dn_mask |= DN_ATTRIB; if (ia_valid & ATTR_GID) dn_mask |= DN_ATTRIB; + if (ia_valid & ATTR_XID) + dn_mask |= DN_ATTRIB; if (ia_valid & ATTR_SIZE) dn_mask |= DN_MODIFY; /* both times implies a utime(s) call */ @@ -130,14 +184,17 @@ int setattr_mask(unsigned int ia_valid) int notify_change(struct dentry * dentry, struct iattr * attr) { struct inode *inode = dentry->d_inode; - mode_t mode = inode->i_mode; + mode_t mode; int error; - struct timespec now = CURRENT_TIME; + struct timespec now; unsigned int ia_valid = attr->ia_valid; if (!inode) BUG(); + mode = inode->i_mode; + now = current_fs_time(inode->i_sb); + attr->ia_ctime = now; if (!(ia_valid & ATTR_ATIME_SET)) attr->ia_atime = now; @@ -166,6 +223,9 @@ int notify_change(struct dentry * dentry, struct iattr * attr) if (!attr->ia_valid) return 0; + if (ia_valid & ATTR_SIZE) + down_write(&dentry->d_inode->i_alloc_sem); + if (inode->i_op && inode->i_op->setattr) { error = security_inode_setattr(dentry, attr); if (!error) @@ -176,12 +236,17 @@ int notify_change(struct dentry * dentry, struct iattr * attr) error = security_inode_setattr(dentry, attr); if (!error) { if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) || - (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) + (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid) || + (ia_valid & ATTR_XID && attr->ia_xid != inode->i_xid)) error = DQUOT_TRANSFER(inode, attr) ? -EDQUOT : 0; if (!error) error = inode_setattr(inode, attr); } } + + if (ia_valid & ATTR_SIZE) + up_write(&dentry->d_inode->i_alloc_sem); + if (!error) { unsigned long dn_mask = setattr_mask(ia_valid); if (dn_mask)