Root/fs/attr.c

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/quotaops.h>
16#include <linux/security.h>
17
18/* Taken over from the old code... */
19
20/* POSIX UID/GID verification for setting inode attributes. */
21int inode_change_ok(struct inode *inode, struct iattr *attr)
22{
23    int retval = -EPERM;
24    unsigned int ia_valid = attr->ia_valid;
25
26    /* If force is set do it anyway. */
27    if (ia_valid & ATTR_FORCE)
28        goto fine;
29
30    /* Make sure a caller can chown. */
31    if ((ia_valid & ATTR_UID) &&
32        (current_fsuid() != inode->i_uid ||
33         attr->ia_uid != inode->i_uid) && !capable(CAP_CHOWN))
34        goto error;
35
36    /* Make sure caller can chgrp. */
37    if ((ia_valid & ATTR_GID) &&
38        (current_fsuid() != inode->i_uid ||
39        (!in_group_p(attr->ia_gid) && attr->ia_gid != inode->i_gid)) &&
40        !capable(CAP_CHOWN))
41        goto error;
42
43    /* Make sure a caller can chmod. */
44    if (ia_valid & ATTR_MODE) {
45        if (!is_owner_or_cap(inode))
46            goto error;
47        /* Also check the setgid bit! */
48        if (!in_group_p((ia_valid & ATTR_GID) ? attr->ia_gid :
49                inode->i_gid) && !capable(CAP_FSETID))
50            attr->ia_mode &= ~S_ISGID;
51    }
52
53    /* Check for setting the inode time. */
54    if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET)) {
55        if (!is_owner_or_cap(inode))
56            goto error;
57    }
58fine:
59    retval = 0;
60error:
61    return retval;
62}
63
64EXPORT_SYMBOL(inode_change_ok);
65
66int inode_setattr(struct inode * inode, struct iattr * attr)
67{
68    unsigned int ia_valid = attr->ia_valid;
69
70    if (ia_valid & ATTR_SIZE &&
71        attr->ia_size != i_size_read(inode)) {
72        int error = vmtruncate(inode, attr->ia_size);
73        if (error)
74            return error;
75    }
76
77    if (ia_valid & ATTR_UID)
78        inode->i_uid = attr->ia_uid;
79    if (ia_valid & ATTR_GID)
80        inode->i_gid = attr->ia_gid;
81    if (ia_valid & ATTR_ATIME)
82        inode->i_atime = timespec_trunc(attr->ia_atime,
83                        inode->i_sb->s_time_gran);
84    if (ia_valid & ATTR_MTIME)
85        inode->i_mtime = timespec_trunc(attr->ia_mtime,
86                        inode->i_sb->s_time_gran);
87    if (ia_valid & ATTR_CTIME)
88        inode->i_ctime = timespec_trunc(attr->ia_ctime,
89                        inode->i_sb->s_time_gran);
90    if (ia_valid & ATTR_MODE) {
91        umode_t mode = attr->ia_mode;
92
93        if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID))
94            mode &= ~S_ISGID;
95        inode->i_mode = mode;
96    }
97    mark_inode_dirty(inode);
98
99    return 0;
100}
101EXPORT_SYMBOL(inode_setattr);
102
103int notify_change(struct dentry * dentry, struct iattr * attr)
104{
105    struct inode *inode = dentry->d_inode;
106    mode_t mode = inode->i_mode;
107    int error;
108    struct timespec now;
109    unsigned int ia_valid = attr->ia_valid;
110
111    if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID | ATTR_TIMES_SET)) {
112        if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
113            return -EPERM;
114    }
115
116    now = current_fs_time(inode->i_sb);
117
118    attr->ia_ctime = now;
119    if (!(ia_valid & ATTR_ATIME_SET))
120        attr->ia_atime = now;
121    if (!(ia_valid & ATTR_MTIME_SET))
122        attr->ia_mtime = now;
123    if (ia_valid & ATTR_KILL_PRIV) {
124        attr->ia_valid &= ~ATTR_KILL_PRIV;
125        ia_valid &= ~ATTR_KILL_PRIV;
126        error = security_inode_need_killpriv(dentry);
127        if (error > 0)
128            error = security_inode_killpriv(dentry);
129        if (error)
130            return error;
131    }
132
133    /*
134     * We now pass ATTR_KILL_S*ID to the lower level setattr function so
135     * that the function has the ability to reinterpret a mode change
136     * that's due to these bits. This adds an implicit restriction that
137     * no function will ever call notify_change with both ATTR_MODE and
138     * ATTR_KILL_S*ID set.
139     */
140    if ((ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID)) &&
141        (ia_valid & ATTR_MODE))
142        BUG();
143
144    if (ia_valid & ATTR_KILL_SUID) {
145        if (mode & S_ISUID) {
146            ia_valid = attr->ia_valid |= ATTR_MODE;
147            attr->ia_mode = (inode->i_mode & ~S_ISUID);
148        }
149    }
150    if (ia_valid & ATTR_KILL_SGID) {
151        if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
152            if (!(ia_valid & ATTR_MODE)) {
153                ia_valid = attr->ia_valid |= ATTR_MODE;
154                attr->ia_mode = inode->i_mode;
155            }
156            attr->ia_mode &= ~S_ISGID;
157        }
158    }
159    if (!(attr->ia_valid & ~(ATTR_KILL_SUID | ATTR_KILL_SGID)))
160        return 0;
161
162    error = security_inode_setattr(dentry, attr);
163    if (error)
164        return error;
165
166    if (ia_valid & ATTR_SIZE)
167        down_write(&dentry->d_inode->i_alloc_sem);
168
169    if (inode->i_op && inode->i_op->setattr) {
170        error = inode->i_op->setattr(dentry, attr);
171    } else {
172        error = inode_change_ok(inode, attr);
173        if (!error) {
174            if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) ||
175                (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid))
176                error = vfs_dq_transfer(inode, attr) ?
177                    -EDQUOT : 0;
178            if (!error)
179                error = inode_setattr(inode, attr);
180        }
181    }
182
183    if (ia_valid & ATTR_SIZE)
184        up_write(&dentry->d_inode->i_alloc_sem);
185
186    if (!error)
187        fsnotify_change(dentry, ia_valid);
188
189    return error;
190}
191
192EXPORT_SYMBOL(notify_change);
193

Archive Download this file



interactive