Root/fs/attr.c

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

Archive Download this file



interactive