diff options
Diffstat (limited to 'fs/sysfs/inode.c')
-rw-r--r-- | fs/sysfs/inode.c | 134 |
1 files changed, 98 insertions, 36 deletions
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index 555f0ff988df..2b6a8d9de73d 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c | |||
@@ -18,6 +18,8 @@ | |||
18 | #include <linux/capability.h> | 18 | #include <linux/capability.h> |
19 | #include <linux/errno.h> | 19 | #include <linux/errno.h> |
20 | #include <linux/sched.h> | 20 | #include <linux/sched.h> |
21 | #include <linux/xattr.h> | ||
22 | #include <linux/security.h> | ||
21 | #include "sysfs.h" | 23 | #include "sysfs.h" |
22 | 24 | ||
23 | extern struct super_block * sysfs_sb; | 25 | extern struct super_block * sysfs_sb; |
@@ -35,6 +37,7 @@ static struct backing_dev_info sysfs_backing_dev_info = { | |||
35 | 37 | ||
36 | static const struct inode_operations sysfs_inode_operations ={ | 38 | static const struct inode_operations sysfs_inode_operations ={ |
37 | .setattr = sysfs_setattr, | 39 | .setattr = sysfs_setattr, |
40 | .setxattr = sysfs_setxattr, | ||
38 | }; | 41 | }; |
39 | 42 | ||
40 | int __init sysfs_inode_init(void) | 43 | int __init sysfs_inode_init(void) |
@@ -42,18 +45,37 @@ int __init sysfs_inode_init(void) | |||
42 | return bdi_init(&sysfs_backing_dev_info); | 45 | return bdi_init(&sysfs_backing_dev_info); |
43 | } | 46 | } |
44 | 47 | ||
48 | struct sysfs_inode_attrs *sysfs_init_inode_attrs(struct sysfs_dirent *sd) | ||
49 | { | ||
50 | struct sysfs_inode_attrs *attrs; | ||
51 | struct iattr *iattrs; | ||
52 | |||
53 | attrs = kzalloc(sizeof(struct sysfs_inode_attrs), GFP_KERNEL); | ||
54 | if (!attrs) | ||
55 | return NULL; | ||
56 | iattrs = &attrs->ia_iattr; | ||
57 | |||
58 | /* assign default attributes */ | ||
59 | iattrs->ia_mode = sd->s_mode; | ||
60 | iattrs->ia_uid = 0; | ||
61 | iattrs->ia_gid = 0; | ||
62 | iattrs->ia_atime = iattrs->ia_mtime = iattrs->ia_ctime = CURRENT_TIME; | ||
63 | |||
64 | return attrs; | ||
65 | } | ||
45 | int sysfs_setattr(struct dentry * dentry, struct iattr * iattr) | 66 | int sysfs_setattr(struct dentry * dentry, struct iattr * iattr) |
46 | { | 67 | { |
47 | struct inode * inode = dentry->d_inode; | 68 | struct inode * inode = dentry->d_inode; |
48 | struct sysfs_dirent * sd = dentry->d_fsdata; | 69 | struct sysfs_dirent * sd = dentry->d_fsdata; |
49 | struct iattr * sd_iattr; | 70 | struct sysfs_inode_attrs *sd_attrs; |
71 | struct iattr *iattrs; | ||
50 | unsigned int ia_valid = iattr->ia_valid; | 72 | unsigned int ia_valid = iattr->ia_valid; |
51 | int error; | 73 | int error; |
52 | 74 | ||
53 | if (!sd) | 75 | if (!sd) |
54 | return -EINVAL; | 76 | return -EINVAL; |
55 | 77 | ||
56 | sd_iattr = sd->s_iattr; | 78 | sd_attrs = sd->s_iattr; |
57 | 79 | ||
58 | error = inode_change_ok(inode, iattr); | 80 | error = inode_change_ok(inode, iattr); |
59 | if (error) | 81 | if (error) |
@@ -65,42 +87,77 @@ int sysfs_setattr(struct dentry * dentry, struct iattr * iattr) | |||
65 | if (error) | 87 | if (error) |
66 | return error; | 88 | return error; |
67 | 89 | ||
68 | if (!sd_iattr) { | 90 | if (!sd_attrs) { |
69 | /* setting attributes for the first time, allocate now */ | 91 | /* setting attributes for the first time, allocate now */ |
70 | sd_iattr = kzalloc(sizeof(struct iattr), GFP_KERNEL); | 92 | sd_attrs = sysfs_init_inode_attrs(sd); |
71 | if (!sd_iattr) | 93 | if (!sd_attrs) |
72 | return -ENOMEM; | 94 | return -ENOMEM; |
73 | /* assign default attributes */ | 95 | sd->s_iattr = sd_attrs; |
74 | sd_iattr->ia_mode = sd->s_mode; | 96 | } else { |
75 | sd_iattr->ia_uid = 0; | 97 | /* attributes were changed at least once in past */ |
76 | sd_iattr->ia_gid = 0; | 98 | iattrs = &sd_attrs->ia_iattr; |
77 | sd_iattr->ia_atime = sd_iattr->ia_mtime = sd_iattr->ia_ctime = CURRENT_TIME; | 99 | |
78 | sd->s_iattr = sd_iattr; | 100 | if (ia_valid & ATTR_UID) |
101 | iattrs->ia_uid = iattr->ia_uid; | ||
102 | if (ia_valid & ATTR_GID) | ||
103 | iattrs->ia_gid = iattr->ia_gid; | ||
104 | if (ia_valid & ATTR_ATIME) | ||
105 | iattrs->ia_atime = timespec_trunc(iattr->ia_atime, | ||
106 | inode->i_sb->s_time_gran); | ||
107 | if (ia_valid & ATTR_MTIME) | ||
108 | iattrs->ia_mtime = timespec_trunc(iattr->ia_mtime, | ||
109 | inode->i_sb->s_time_gran); | ||
110 | if (ia_valid & ATTR_CTIME) | ||
111 | iattrs->ia_ctime = timespec_trunc(iattr->ia_ctime, | ||
112 | inode->i_sb->s_time_gran); | ||
113 | if (ia_valid & ATTR_MODE) { | ||
114 | umode_t mode = iattr->ia_mode; | ||
115 | |||
116 | if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID)) | ||
117 | mode &= ~S_ISGID; | ||
118 | iattrs->ia_mode = sd->s_mode = mode; | ||
119 | } | ||
79 | } | 120 | } |
121 | return error; | ||
122 | } | ||
80 | 123 | ||
81 | /* attributes were changed atleast once in past */ | 124 | int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value, |
82 | 125 | size_t size, int flags) | |
83 | if (ia_valid & ATTR_UID) | 126 | { |
84 | sd_iattr->ia_uid = iattr->ia_uid; | 127 | struct sysfs_dirent *sd = dentry->d_fsdata; |
85 | if (ia_valid & ATTR_GID) | 128 | struct sysfs_inode_attrs *iattrs; |
86 | sd_iattr->ia_gid = iattr->ia_gid; | 129 | void *secdata; |
87 | if (ia_valid & ATTR_ATIME) | 130 | int error; |
88 | sd_iattr->ia_atime = timespec_trunc(iattr->ia_atime, | 131 | u32 secdata_len = 0; |
89 | inode->i_sb->s_time_gran); | 132 | |
90 | if (ia_valid & ATTR_MTIME) | 133 | if (!sd) |
91 | sd_iattr->ia_mtime = timespec_trunc(iattr->ia_mtime, | 134 | return -EINVAL; |
92 | inode->i_sb->s_time_gran); | 135 | if (!sd->s_iattr) |
93 | if (ia_valid & ATTR_CTIME) | 136 | sd->s_iattr = sysfs_init_inode_attrs(sd); |
94 | sd_iattr->ia_ctime = timespec_trunc(iattr->ia_ctime, | 137 | if (!sd->s_iattr) |
95 | inode->i_sb->s_time_gran); | 138 | return -ENOMEM; |
96 | if (ia_valid & ATTR_MODE) { | 139 | |
97 | umode_t mode = iattr->ia_mode; | 140 | iattrs = sd->s_iattr; |
98 | 141 | ||
99 | if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID)) | 142 | if (!strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN)) { |
100 | mode &= ~S_ISGID; | 143 | const char *suffix = name + XATTR_SECURITY_PREFIX_LEN; |
101 | sd_iattr->ia_mode = sd->s_mode = mode; | 144 | error = security_inode_setsecurity(dentry->d_inode, suffix, |
102 | } | 145 | value, size, flags); |
146 | if (error) | ||
147 | goto out; | ||
148 | error = security_inode_getsecctx(dentry->d_inode, | ||
149 | &secdata, &secdata_len); | ||
150 | if (error) | ||
151 | goto out; | ||
152 | if (iattrs->ia_secdata) | ||
153 | security_release_secctx(iattrs->ia_secdata, | ||
154 | iattrs->ia_secdata_len); | ||
155 | iattrs->ia_secdata = secdata; | ||
156 | iattrs->ia_secdata_len = secdata_len; | ||
103 | 157 | ||
158 | } else | ||
159 | return -EINVAL; | ||
160 | out: | ||
104 | return error; | 161 | return error; |
105 | } | 162 | } |
106 | 163 | ||
@@ -146,6 +203,7 @@ static int sysfs_count_nlink(struct sysfs_dirent *sd) | |||
146 | static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode) | 203 | static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode) |
147 | { | 204 | { |
148 | struct bin_attribute *bin_attr; | 205 | struct bin_attribute *bin_attr; |
206 | struct sysfs_inode_attrs *iattrs; | ||
149 | 207 | ||
150 | inode->i_private = sysfs_get(sd); | 208 | inode->i_private = sysfs_get(sd); |
151 | inode->i_mapping->a_ops = &sysfs_aops; | 209 | inode->i_mapping->a_ops = &sysfs_aops; |
@@ -154,16 +212,20 @@ static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode) | |||
154 | inode->i_ino = sd->s_ino; | 212 | inode->i_ino = sd->s_ino; |
155 | lockdep_set_class(&inode->i_mutex, &sysfs_inode_imutex_key); | 213 | lockdep_set_class(&inode->i_mutex, &sysfs_inode_imutex_key); |
156 | 214 | ||
157 | if (sd->s_iattr) { | 215 | iattrs = sd->s_iattr; |
216 | if (iattrs) { | ||
158 | /* sysfs_dirent has non-default attributes | 217 | /* sysfs_dirent has non-default attributes |
159 | * get them for the new inode from persistent copy | 218 | * get them for the new inode from persistent copy |
160 | * in sysfs_dirent | 219 | * in sysfs_dirent |
161 | */ | 220 | */ |
162 | set_inode_attr(inode, sd->s_iattr); | 221 | set_inode_attr(inode, &iattrs->ia_iattr); |
222 | if (iattrs->ia_secdata) | ||
223 | security_inode_notifysecctx(inode, | ||
224 | iattrs->ia_secdata, | ||
225 | iattrs->ia_secdata_len); | ||
163 | } else | 226 | } else |
164 | set_default_inode_attr(inode, sd->s_mode); | 227 | set_default_inode_attr(inode, sd->s_mode); |
165 | 228 | ||
166 | |||
167 | /* initialize inode according to type */ | 229 | /* initialize inode according to type */ |
168 | switch (sysfs_type(sd)) { | 230 | switch (sysfs_type(sd)) { |
169 | case SYSFS_DIR: | 231 | case SYSFS_DIR: |