linux/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/capability.h>
  13#include <linux/fsnotify.h>
  14#include <linux/fcntl.h>
  15#include <linux/security.h>
  16
  17/* Taken over from the old code... */
  18
  19/* POSIX UID/GID verification for setting inode attributes. */
  20int inode_change_ok(const struct inode *inode, struct iattr *attr)
  21{
  22        int retval = -EPERM;
  23        unsigned int ia_valid = attr->ia_valid;
  24
  25        /* If force is set do it anyway. */
  26        if (ia_valid & ATTR_FORCE)
  27                goto fine;
  28
  29        /* Make sure a caller can chown. */
  30        if ((ia_valid & ATTR_UID) &&
  31            (current_fsuid() != inode->i_uid ||
  32             attr->ia_uid != inode->i_uid) && !capable(CAP_CHOWN))
  33                goto error;
  34
  35        /* Make sure caller can chgrp. */
  36        if ((ia_valid & ATTR_GID) &&
  37            (current_fsuid() != inode->i_uid ||
  38            (!in_group_p(attr->ia_gid) && attr->ia_gid != inode->i_gid)) &&
  39            !capable(CAP_CHOWN))
  40                goto error;
  41
  42        /* Make sure a caller can chmod. */
  43        if (ia_valid & ATTR_MODE) {
  44                if (!is_owner_or_cap(inode))
  45                        goto error;
  46                /* Also check the setgid bit! */
  47                if (!in_group_p((ia_valid & ATTR_GID) ? attr->ia_gid :
  48                                inode->i_gid) && !capable(CAP_FSETID))
  49                        attr->ia_mode &= ~S_ISGID;
  50        }
  51
  52        /* Check for setting the inode time. */
  53        if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET)) {
  54                if (!is_owner_or_cap(inode))
  55                        goto error;
  56        }
  57fine:
  58        retval = 0;
  59error:
  60        return retval;
  61}
  62EXPORT_SYMBOL(inode_change_ok);
  63
  64/**
  65 * inode_newsize_ok - may this inode be truncated to a given size
  66 * @inode:      the inode to be truncated
  67 * @offset:     the new size to assign to the inode
  68 * @Returns:    0 on success, -ve errno on failure
  69 *
  70 * inode_newsize_ok must be called with i_mutex held.
  71 *
  72 * inode_newsize_ok will check filesystem limits and ulimits to check that the
  73 * new inode size is within limits. inode_newsize_ok will also send SIGXFSZ
  74 * when necessary. Caller must not proceed with inode size change if failure is
  75 * returned. @inode must be a file (not directory), with appropriate
  76 * permissions to allow truncate (inode_newsize_ok does NOT check these
  77 * conditions).
  78 */
  79int inode_newsize_ok(const struct inode *inode, loff_t offset)
  80{
  81        if (inode->i_size < offset) {
  82                unsigned long limit;
  83
  84                limit = rlimit(RLIMIT_FSIZE);
  85                if (limit != RLIM_INFINITY && offset > limit)
  86                        goto out_sig;
  87                if (offset > inode->i_sb->s_maxbytes)
  88                        goto out_big;
  89        } else {
  90                /*
  91                 * truncation of in-use swapfiles is disallowed - it would
  92                 * cause subsequent swapout to scribble on the now-freed
  93                 * blocks.
  94                 */
  95                if (IS_SWAPFILE(inode))
  96                        return -ETXTBSY;
  97        }
  98
  99        return 0;
 100out_sig:
 101        send_sig(SIGXFSZ, current, 0);
 102out_big:
 103        return -EFBIG;
 104}
 105EXPORT_SYMBOL(inode_newsize_ok);
 106
 107/**
 108 * generic_setattr - copy simple metadata updates into the generic inode
 109 * @inode:      the inode to be updated
 110 * @attr:       the new attributes
 111 *
 112 * generic_setattr must be called with i_mutex held.
 113 *
 114 * generic_setattr updates the inode's metadata with that specified
 115 * in attr. Noticably missing is inode size update, which is more complex
 116 * as it requires pagecache updates. See simple_setsize.
 117 *
 118 * The inode is not marked as dirty after this operation. The rationale is
 119 * that for "simple" filesystems, the struct inode is the inode storage.
 120 * The caller is free to mark the inode dirty afterwards if needed.
 121 */
 122void generic_setattr(struct inode *inode, const struct iattr *attr)
 123{
 124        unsigned int ia_valid = attr->ia_valid;
 125
 126        if (ia_valid & ATTR_UID)
 127                inode->i_uid = attr->ia_uid;
 128        if (ia_valid & ATTR_GID)
 129                inode->i_gid = attr->ia_gid;
 130        if (ia_valid & ATTR_ATIME)
 131                inode->i_atime = timespec_trunc(attr->ia_atime,
 132                                                inode->i_sb->s_time_gran);
 133        if (ia_valid & ATTR_MTIME)
 134                inode->i_mtime = timespec_trunc(attr->ia_mtime,
 135                                                inode->i_sb->s_time_gran);
 136        if (ia_valid & ATTR_CTIME)
 137                inode->i_ctime = timespec_trunc(attr->ia_ctime,
 138                                                inode->i_sb->s_time_gran);
 139        if (ia_valid & ATTR_MODE) {
 140                umode_t mode = attr->ia_mode;
 141
 142                if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID))
 143                        mode &= ~S_ISGID;
 144                inode->i_mode = mode;
 145        }
 146}
 147EXPORT_SYMBOL(generic_setattr);
 148
 149/*
 150 * note this function is deprecated, the new truncate sequence should be
 151 * used instead -- see eg. simple_setsize, generic_setattr.
 152 */
 153int inode_setattr(struct inode *inode, const struct iattr *attr)
 154{
 155        unsigned int ia_valid = attr->ia_valid;
 156
 157        if (ia_valid & ATTR_SIZE &&
 158            attr->ia_size != i_size_read(inode)) {
 159                int error;
 160
 161                error = vmtruncate(inode, attr->ia_size);
 162                if (error)
 163                        return error;
 164        }
 165
 166        generic_setattr(inode, attr);
 167
 168        mark_inode_dirty(inode);
 169
 170        return 0;
 171}
 172EXPORT_SYMBOL(inode_setattr);
 173
 174int notify_change(struct dentry * dentry, struct iattr * attr)
 175{
 176        struct inode *inode = dentry->d_inode;
 177        mode_t mode = inode->i_mode;
 178        int error;
 179        struct timespec now;
 180        unsigned int ia_valid = attr->ia_valid;
 181
 182        if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID | ATTR_TIMES_SET)) {
 183                if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
 184                        return -EPERM;
 185        }
 186
 187        now = current_fs_time(inode->i_sb);
 188
 189        attr->ia_ctime = now;
 190        if (!(ia_valid & ATTR_ATIME_SET))
 191                attr->ia_atime = now;
 192        if (!(ia_valid & ATTR_MTIME_SET))
 193                attr->ia_mtime = now;
 194        if (ia_valid & ATTR_KILL_PRIV) {
 195                attr->ia_valid &= ~ATTR_KILL_PRIV;
 196                ia_valid &= ~ATTR_KILL_PRIV;
 197                error = security_inode_need_killpriv(dentry);
 198                if (error > 0)
 199                        error = security_inode_killpriv(dentry);
 200                if (error)
 201                        return error;
 202        }
 203
 204        /*
 205         * We now pass ATTR_KILL_S*ID to the lower level setattr function so
 206         * that the function has the ability to reinterpret a mode change
 207         * that's due to these bits. This adds an implicit restriction that
 208         * no function will ever call notify_change with both ATTR_MODE and
 209         * ATTR_KILL_S*ID set.
 210         */
 211        if ((ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID)) &&
 212            (ia_valid & ATTR_MODE))
 213                BUG();
 214
 215        if (ia_valid & ATTR_KILL_SUID) {
 216                if (mode & S_ISUID) {
 217                        ia_valid = attr->ia_valid |= ATTR_MODE;
 218                        attr->ia_mode = (inode->i_mode & ~S_ISUID);
 219                }
 220        }
 221        if (ia_valid & ATTR_KILL_SGID) {
 222                if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
 223                        if (!(ia_valid & ATTR_MODE)) {
 224                                ia_valid = attr->ia_valid |= ATTR_MODE;
 225                                attr->ia_mode = inode->i_mode;
 226                        }
 227                        attr->ia_mode &= ~S_ISGID;
 228                }
 229        }
 230        if (!(attr->ia_valid & ~(ATTR_KILL_SUID | ATTR_KILL_SGID)))
 231                return 0;
 232
 233        error = security_inode_setattr(dentry, attr);
 234        if (error)
 235                return error;
 236
 237        if (ia_valid & ATTR_SIZE)
 238                down_write(&dentry->d_inode->i_alloc_sem);
 239
 240        if (inode->i_op && inode->i_op->setattr) {
 241                error = inode->i_op->setattr(dentry, attr);
 242        } else {
 243                error = inode_change_ok(inode, attr);
 244                if (!error)
 245                        error = inode_setattr(inode, attr);
 246        }
 247
 248        if (ia_valid & ATTR_SIZE)
 249                up_write(&dentry->d_inode->i_alloc_sem);
 250
 251        if (!error)
 252                fsnotify_change(dentry, ia_valid);
 253
 254        return error;
 255}
 256
 257EXPORT_SYMBOL(notify_change);
 258
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.