RHEL4/fs/attr.c
<<
>>
Prefs
   1/*
   2 *  linux/fs/attr.c
   3 *
   4 *  Copyright (C) 1991, 1992  Linus Torvalds
   5 *  changes by Thomas Schoebel-Theuer
   6 */
   7
   8#include <linux/module.h>
   9#include <linux/time.h>
  10#include <linux/mm.h>
  11#include <linux/string.h>
  12#include <linux/smp_lock.h>
  13#include <linux/dnotify.h>
  14#include <linux/fcntl.h>
  15#include <linux/quotaops.h>
  16#include <linux/security.h>
  17#include <linux/time.h>
  18#include <linux/audit.h>
  19
  20/* Taken over from the old code... */
  21
  22/* POSIX UID/GID verification for setting inode attributes. */
  23int inode_change_ok(struct inode *inode, struct iattr *attr)
  24{
  25        int retval = -EPERM;
  26        unsigned int ia_valid = attr->ia_valid;
  27
  28        /* If force is set do it anyway. */
  29        if (ia_valid & ATTR_FORCE)
  30                goto fine;
  31
  32        /* Make sure a caller can chown. */
  33        if ((ia_valid & ATTR_UID) &&
  34            (current->fsuid != inode->i_uid ||
  35             attr->ia_uid != inode->i_uid) && !capable(CAP_CHOWN))
  36                goto error;
  37
  38        /* Make sure caller can chgrp. */
  39        if ((ia_valid & ATTR_GID) &&
  40            (current->fsuid != inode->i_uid ||
  41            (!in_group_p(attr->ia_gid) && attr->ia_gid != inode->i_gid)) &&
  42            !capable(CAP_CHOWN))
  43                goto error;
  44
  45        /* Make sure a caller can chmod. */
  46        if (ia_valid & ATTR_MODE) {
  47                if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
  48                        goto error;
  49                /* Also check the setgid bit! */
  50                if (!in_group_p((ia_valid & ATTR_GID) ? attr->ia_gid :
  51                                inode->i_gid) && !capable(CAP_FSETID))
  52                        attr->ia_mode &= ~S_ISGID;
  53        }
  54
  55        /* Check for setting the inode time. */
  56        if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET)) {
  57                if (current->fsuid != inode->i_uid && !capable(CAP_FOWNER))
  58                        goto error;
  59        }
  60fine:
  61        retval = 0;
  62error:
  63        return retval;
  64}
  65
  66EXPORT_SYMBOL(inode_change_ok);
  67
  68int inode_setattr(struct inode * inode, struct iattr * attr)
  69{
  70        unsigned int ia_valid = attr->ia_valid;
  71        int error = 0;
  72
  73        audit_notify_watch(inode, MAY_WRITE);   
  74
  75        if (ia_valid & ATTR_SIZE &&
  76            attr->ia_size != i_size_read(inode)) {
  77                error = vmtruncate(inode, attr->ia_size);
  78                if (error || (ia_valid == ATTR_SIZE))
  79                        goto out;
  80        }
  81
  82        if (ia_valid & ATTR_UID)
  83                inode->i_uid = attr->ia_uid;
  84        if (ia_valid & ATTR_GID)
  85                inode->i_gid = attr->ia_gid;
  86        if (ia_valid & ATTR_ATIME)
  87                inode->i_atime = timespec_trunc(attr->ia_atime,
  88                                                get_sb_time_gran(inode->i_sb));
  89        if (ia_valid & ATTR_MTIME)
  90                inode->i_mtime = timespec_trunc(attr->ia_mtime,
  91                                                get_sb_time_gran(inode->i_sb));
  92        if (ia_valid & ATTR_CTIME)
  93                inode->i_ctime = timespec_trunc(attr->ia_ctime,
  94                                                get_sb_time_gran(inode->i_sb));
  95        if (ia_valid & ATTR_MODE) {
  96                umode_t mode = attr->ia_mode;
  97
  98                if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID))
  99                        mode &= ~S_ISGID;
 100                inode->i_mode = mode;
 101        }
 102        mark_inode_dirty(inode);
 103out:
 104        return error;
 105}
 106
 107EXPORT_SYMBOL(inode_setattr);
 108
 109int setattr_mask(unsigned int ia_valid)
 110{
 111        unsigned long dn_mask = 0;
 112
 113        if (ia_valid & ATTR_UID)
 114                dn_mask |= DN_ATTRIB;
 115        if (ia_valid & ATTR_GID)
 116                dn_mask |= DN_ATTRIB;
 117        if (ia_valid & ATTR_SIZE)
 118                dn_mask |= DN_MODIFY;
 119        /* both times implies a utime(s) call */
 120        if ((ia_valid & (ATTR_ATIME|ATTR_MTIME)) == (ATTR_ATIME|ATTR_MTIME))
 121                dn_mask |= DN_ATTRIB;
 122        else if (ia_valid & ATTR_ATIME)
 123                dn_mask |= DN_ACCESS;
 124        else if (ia_valid & ATTR_MTIME)
 125                dn_mask |= DN_MODIFY;
 126        if (ia_valid & ATTR_MODE)
 127                dn_mask |= DN_ATTRIB;
 128        return dn_mask;
 129}
 130
 131int notify_change(struct dentry * dentry, struct iattr * attr)
 132{
 133        struct inode *inode = dentry->d_inode;
 134        int error;
 135        struct timespec now;
 136        unsigned int ia_valid = attr->ia_valid;
 137        mode_t ia_mode = attr->ia_mode;
 138
 139        if (!inode)
 140                BUG();
 141
 142        now = current_fs_time(inode->i_sb);
 143
 144        attr->ia_ctime = now;
 145        if (!(ia_valid & ATTR_ATIME_SET))
 146                attr->ia_atime = now;
 147        if (!(ia_valid & ATTR_MTIME_SET))
 148                attr->ia_mtime = now;
 149        if (ia_valid & ATTR_KILL_SUID) {
 150                ia_valid &= ~ATTR_KILL_SUID;
 151                if (inode->i_mode & S_ISUID) {
 152                        if (!(ia_valid & ATTR_MODE)) {
 153                                ia_valid |= ATTR_MODE;
 154                                ia_mode = inode->i_mode;
 155                        }
 156                        ia_mode &= ~S_ISUID;
 157                }
 158        }
 159        if (ia_valid & ATTR_KILL_SGID) {
 160                ia_valid &= ~ATTR_KILL_SGID;
 161                if ((inode->i_mode & (S_ISGID | S_IXGRP)) ==
 162                    (S_ISGID | S_IXGRP)) {
 163                        if (!(ia_valid & ATTR_MODE)) {
 164                                ia_valid |= ATTR_MODE;
 165                                ia_mode = inode->i_mode;
 166                        }
 167                        ia_mode &= ~S_ISGID;
 168                }
 169        }
 170
 171        if (!ia_valid)
 172                return 0;
 173
 174        /*
 175         * For RHEL, we've added the S_NOATTRKILL flag to allow filesystems
 176         * to opt-out of ATTR_KILL_S*ID processing. The ATTR_KILL_S*ID bits
 177         * are now handled in two stages. First, we calculate what the
 178         * ia_valid and the ia_mode would look like if we were to allow the
 179         * ATTR_KILL_S*ID bits to modify them. We then make the decision of
 180         * whether to allow the modification to occur. We could just skip
 181         * all of the ATTR_KILL_S*ID processing altogether, but we need it
 182         * for inotify. If a process is watching for mode changes, we want
 183         * it to be notified if we suspect that the server will be doing the
 184         * mode change for us.
 185         */
 186
 187        if ((ia_valid & ATTR_MODE) && !(inode->i_flags & S_NOATTRKILL)) {
 188                attr->ia_valid = ia_valid;
 189                attr->ia_mode = ia_mode;
 190        }
 191
 192        if (ia_valid & ATTR_SIZE)
 193                down_write(&dentry->d_inode->i_alloc_sem);
 194
 195        if (inode->i_op && inode->i_op->setattr) {
 196                audit_notify_watch(inode, MAY_WRITE);
 197                error = security_inode_setattr(dentry, attr);
 198                if (!error)
 199                        error = inode->i_op->setattr(dentry, attr);
 200        } else {
 201                error = inode_change_ok(inode, attr);
 202                if (!error)
 203                        error = security_inode_setattr(dentry, attr);
 204                if (!error) {
 205                        if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) ||
 206                            (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid))
 207                                error = DQUOT_TRANSFER(inode, attr) ? -EDQUOT : 0;
 208                        if (!error)
 209                                error = inode_setattr(inode, attr);
 210                }
 211        }
 212
 213        if (ia_valid & ATTR_SIZE)
 214                up_write(&dentry->d_inode->i_alloc_sem);
 215
 216        if (!error) {
 217                unsigned long dn_mask = setattr_mask(ia_valid);
 218                if (dn_mask)
 219                        dnotify_parent(dentry, dn_mask);
 220        }
 221        return error;
 222}
 223
 224EXPORT_SYMBOL(notify_change);
 225