diff options
Diffstat (limited to 'fs/sysfs')
-rw-r--r-- | fs/sysfs/dir.c | 1 | ||||
-rw-r--r-- | fs/sysfs/inode.c | 134 | ||||
-rw-r--r-- | fs/sysfs/symlink.c | 2 | ||||
-rw-r--r-- | fs/sysfs/sysfs.h | 12 |
4 files changed, 112 insertions, 37 deletions
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 14f2d71ea3ce..0050fc40e8c9 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c | |||
@@ -760,6 +760,7 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, | |||
760 | const struct inode_operations sysfs_dir_inode_operations = { | 760 | const struct inode_operations sysfs_dir_inode_operations = { |
761 | .lookup = sysfs_lookup, | 761 | .lookup = sysfs_lookup, |
762 | .setattr = sysfs_setattr, | 762 | .setattr = sysfs_setattr, |
763 | .setxattr = sysfs_setxattr, | ||
763 | }; | 764 | }; |
764 | 765 | ||
765 | static void remove_dir(struct sysfs_dirent *sd) | 766 | static void remove_dir(struct sysfs_dirent *sd) |
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index e57f98e54fce..e28cecf179f5 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; |
@@ -36,6 +38,7 @@ static struct backing_dev_info sysfs_backing_dev_info = { | |||
36 | 38 | ||
37 | static const struct inode_operations sysfs_inode_operations ={ | 39 | static const struct inode_operations sysfs_inode_operations ={ |
38 | .setattr = sysfs_setattr, | 40 | .setattr = sysfs_setattr, |
41 | .setxattr = sysfs_setxattr, | ||
39 | }; | 42 | }; |
40 | 43 | ||
41 | int __init sysfs_inode_init(void) | 44 | int __init sysfs_inode_init(void) |
@@ -43,18 +46,37 @@ int __init sysfs_inode_init(void) | |||
43 | return bdi_init(&sysfs_backing_dev_info); | 46 | return bdi_init(&sysfs_backing_dev_info); |
44 | } | 47 | } |
45 | 48 | ||
49 | struct sysfs_inode_attrs *sysfs_init_inode_attrs(struct sysfs_dirent *sd) | ||
50 | { | ||
51 | struct sysfs_inode_attrs *attrs; | ||
52 | struct iattr *iattrs; | ||
53 | |||
54 | attrs = kzalloc(sizeof(struct sysfs_inode_attrs), GFP_KERNEL); | ||
55 | if (!attrs) | ||
56 | return NULL; | ||
57 | iattrs = &attrs->ia_iattr; | ||
58 | |||
59 | /* assign default attributes */ | ||
60 | iattrs->ia_mode = sd->s_mode; | ||
61 | iattrs->ia_uid = 0; | ||
62 | iattrs->ia_gid = 0; | ||
63 | iattrs->ia_atime = iattrs->ia_mtime = iattrs->ia_ctime = CURRENT_TIME; | ||
64 | |||
65 | return attrs; | ||
66 | } | ||
46 | int sysfs_setattr(struct dentry * dentry, struct iattr * iattr) | 67 | int sysfs_setattr(struct dentry * dentry, struct iattr * iattr) |
47 | { | 68 | { |
48 | struct inode * inode = dentry->d_inode; | 69 | struct inode * inode = dentry->d_inode; |
49 | struct sysfs_dirent * sd = dentry->d_fsdata; | 70 | struct sysfs_dirent * sd = dentry->d_fsdata; |
50 | struct iattr * sd_iattr; | 71 | struct sysfs_inode_attrs *sd_attrs; |
72 | struct iattr *iattrs; | ||
51 | unsigned int ia_valid = iattr->ia_valid; | 73 | unsigned int ia_valid = iattr->ia_valid; |
52 | int error; | 74 | int error; |
53 | 75 | ||
54 | if (!sd) | 76 | if (!sd) |
55 | return -EINVAL; | 77 | return -EINVAL; |
56 | 78 | ||
57 | sd_iattr = sd->s_iattr; | 79 | sd_attrs = sd->s_iattr; |
58 | 80 | ||
59 | error = inode_change_ok(inode, iattr); | 81 | error = inode_change_ok(inode, iattr); |
60 | if (error) | 82 | if (error) |
@@ -66,42 +88,77 @@ int sysfs_setattr(struct dentry * dentry, struct iattr * iattr) | |||
66 | if (error) | 88 | if (error) |
67 | return error; | 89 | return error; |
68 | 90 | ||
69 | if (!sd_iattr) { | 91 | if (!sd_attrs) { |
70 | /* setting attributes for the first time, allocate now */ | 92 | /* setting attributes for the first time, allocate now */ |
71 | sd_iattr = kzalloc(sizeof(struct iattr), GFP_KERNEL); | 93 | sd_attrs = sysfs_init_inode_attrs(sd); |
72 | if (!sd_iattr) | 94 | if (!sd_attrs) |
73 | return -ENOMEM; | 95 | return -ENOMEM; |
74 | /* assign default attributes */ | 96 | sd->s_iattr = sd_attrs; |
75 | sd_iattr->ia_mode = sd->s_mode; | 97 | } else { |
76 | sd_iattr->ia_uid = 0; | 98 | /* attributes were changed at least once in past */ |
77 | sd_iattr->ia_gid = 0; | 99 | iattrs = &sd_attrs->ia_iattr; |
78 | sd_iattr->ia_atime = sd_iattr->ia_mtime = sd_iattr->ia_ctime = CURRENT_TIME; | 100 | |
79 | sd->s_iattr = sd_iattr; | 101 | if (ia_valid & ATTR_UID) |
102 | iattrs->ia_uid = iattr->ia_uid; | ||
103 | if (ia_valid & ATTR_GID) | ||
104 | iattrs->ia_gid = iattr->ia_gid; | ||
105 | if (ia_valid & ATTR_ATIME) | ||
106 | iattrs->ia_atime = timespec_trunc(iattr->ia_atime, | ||
107 | inode->i_sb->s_time_gran); | ||
108 | if (ia_valid & ATTR_MTIME) | ||
109 | iattrs->ia_mtime = timespec_trunc(iattr->ia_mtime, | ||
110 | inode->i_sb->s_time_gran); | ||
111 | if (ia_valid & ATTR_CTIME) | ||
112 | iattrs->ia_ctime = timespec_trunc(iattr->ia_ctime, | ||
113 | inode->i_sb->s_time_gran); | ||
114 | if (ia_valid & ATTR_MODE) { | ||
115 | umode_t mode = iattr->ia_mode; | ||
116 | |||
117 | if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID)) | ||
118 | mode &= ~S_ISGID; | ||
119 | iattrs->ia_mode = sd->s_mode = mode; | ||
120 | } | ||
80 | } | 121 | } |
122 | return error; | ||
123 | } | ||
81 | 124 | ||
82 | /* attributes were changed atleast once in past */ | 125 | int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value, |
83 | 126 | size_t size, int flags) | |
84 | if (ia_valid & ATTR_UID) | 127 | { |
85 | sd_iattr->ia_uid = iattr->ia_uid; | 128 | struct sysfs_dirent *sd = dentry->d_fsdata; |
86 | if (ia_valid & ATTR_GID) | 129 | struct sysfs_inode_attrs *iattrs; |
87 | sd_iattr->ia_gid = iattr->ia_gid; | 130 | void *secdata; |
88 | if (ia_valid & ATTR_ATIME) | 131 | int error; |
89 | sd_iattr->ia_atime = timespec_trunc(iattr->ia_atime, | 132 | u32 secdata_len = 0; |
90 | inode->i_sb->s_time_gran); | 133 | |
91 | if (ia_valid & ATTR_MTIME) | 134 | if (!sd) |
92 | sd_iattr->ia_mtime = timespec_trunc(iattr->ia_mtime, | 135 | return -EINVAL; |
93 | inode->i_sb->s_time_gran); | 136 | if (!sd->s_iattr) |
94 | if (ia_valid & ATTR_CTIME) | 137 | sd->s_iattr = sysfs_init_inode_attrs(sd); |
95 | sd_iattr->ia_ctime = timespec_trunc(iattr->ia_ctime, | 138 | if (!sd->s_iattr) |
96 | inode->i_sb->s_time_gran); | 139 | return -ENOMEM; |
97 | if (ia_valid & ATTR_MODE) { | 140 | |
98 | umode_t mode = iattr->ia_mode; | 141 | iattrs = sd->s_iattr; |
99 | 142 | ||
100 | if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID)) | 143 | if (!strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN)) { |
101 | mode &= ~S_ISGID; | 144 | const char *suffix = name + XATTR_SECURITY_PREFIX_LEN; |
102 | sd_iattr->ia_mode = sd->s_mode = mode; | 145 | error = security_inode_setsecurity(dentry->d_inode, suffix, |
103 | } | 146 | value, size, flags); |
147 | if (error) | ||
148 | goto out; | ||
149 | error = security_inode_getsecctx(dentry->d_inode, | ||
150 | &secdata, &secdata_len); | ||
151 | if (error) | ||
152 | goto out; | ||
153 | if (iattrs->ia_secdata) | ||
154 | security_release_secctx(iattrs->ia_secdata, | ||
155 | iattrs->ia_secdata_len); | ||
156 | iattrs->ia_secdata = secdata; | ||
157 | iattrs->ia_secdata_len = secdata_len; | ||
104 | 158 | ||
159 | } else | ||
160 | return -EINVAL; | ||
161 | out: | ||
105 | return error; | 162 | return error; |
106 | } | 163 | } |
107 | 164 | ||
@@ -147,6 +204,7 @@ static int sysfs_count_nlink(struct sysfs_dirent *sd) | |||
147 | static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode) | 204 | static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode) |
148 | { | 205 | { |
149 | struct bin_attribute *bin_attr; | 206 | struct bin_attribute *bin_attr; |
207 | struct sysfs_inode_attrs *iattrs; | ||
150 | 208 | ||
151 | inode->i_private = sysfs_get(sd); | 209 | inode->i_private = sysfs_get(sd); |
152 | inode->i_mapping->a_ops = &sysfs_aops; | 210 | inode->i_mapping->a_ops = &sysfs_aops; |
@@ -155,16 +213,20 @@ static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode) | |||
155 | inode->i_ino = sd->s_ino; | 213 | inode->i_ino = sd->s_ino; |
156 | lockdep_set_class(&inode->i_mutex, &sysfs_inode_imutex_key); | 214 | lockdep_set_class(&inode->i_mutex, &sysfs_inode_imutex_key); |
157 | 215 | ||
158 | if (sd->s_iattr) { | 216 | iattrs = sd->s_iattr; |
217 | if (iattrs) { | ||
159 | /* sysfs_dirent has non-default attributes | 218 | /* sysfs_dirent has non-default attributes |
160 | * get them for the new inode from persistent copy | 219 | * get them for the new inode from persistent copy |
161 | * in sysfs_dirent | 220 | * in sysfs_dirent |
162 | */ | 221 | */ |
163 | set_inode_attr(inode, sd->s_iattr); | 222 | set_inode_attr(inode, &iattrs->ia_iattr); |
223 | if (iattrs->ia_secdata) | ||
224 | security_inode_notifysecctx(inode, | ||
225 | iattrs->ia_secdata, | ||
226 | iattrs->ia_secdata_len); | ||
164 | } else | 227 | } else |
165 | set_default_inode_attr(inode, sd->s_mode); | 228 | set_default_inode_attr(inode, sd->s_mode); |
166 | 229 | ||
167 | |||
168 | /* initialize inode according to type */ | 230 | /* initialize inode according to type */ |
169 | switch (sysfs_type(sd)) { | 231 | switch (sysfs_type(sd)) { |
170 | case SYSFS_DIR: | 232 | case SYSFS_DIR: |
diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index 1d897ad808e0..c5081ad77026 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/kobject.h> | 16 | #include <linux/kobject.h> |
17 | #include <linux/namei.h> | 17 | #include <linux/namei.h> |
18 | #include <linux/mutex.h> | 18 | #include <linux/mutex.h> |
19 | #include <linux/security.h> | ||
19 | 20 | ||
20 | #include "sysfs.h" | 21 | #include "sysfs.h" |
21 | 22 | ||
@@ -209,6 +210,7 @@ static void sysfs_put_link(struct dentry *dentry, struct nameidata *nd, void *co | |||
209 | } | 210 | } |
210 | 211 | ||
211 | const struct inode_operations sysfs_symlink_inode_operations = { | 212 | const struct inode_operations sysfs_symlink_inode_operations = { |
213 | .setxattr = sysfs_setxattr, | ||
212 | .readlink = generic_readlink, | 214 | .readlink = generic_readlink, |
213 | .follow_link = sysfs_follow_link, | 215 | .follow_link = sysfs_follow_link, |
214 | .put_link = sysfs_put_link, | 216 | .put_link = sysfs_put_link, |
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index 3fa0d98481e2..af4c4e7482ac 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h | |||
@@ -8,6 +8,8 @@ | |||
8 | * This file is released under the GPLv2. | 8 | * This file is released under the GPLv2. |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/fs.h> | ||
12 | |||
11 | struct sysfs_open_dirent; | 13 | struct sysfs_open_dirent; |
12 | 14 | ||
13 | /* type-specific structures for sysfs_dirent->s_* union members */ | 15 | /* type-specific structures for sysfs_dirent->s_* union members */ |
@@ -31,6 +33,12 @@ struct sysfs_elem_bin_attr { | |||
31 | struct hlist_head buffers; | 33 | struct hlist_head buffers; |
32 | }; | 34 | }; |
33 | 35 | ||
36 | struct sysfs_inode_attrs { | ||
37 | struct iattr ia_iattr; | ||
38 | void *ia_secdata; | ||
39 | u32 ia_secdata_len; | ||
40 | }; | ||
41 | |||
34 | /* | 42 | /* |
35 | * sysfs_dirent - the building block of sysfs hierarchy. Each and | 43 | * sysfs_dirent - the building block of sysfs hierarchy. Each and |
36 | * every sysfs node is represented by single sysfs_dirent. | 44 | * every sysfs node is represented by single sysfs_dirent. |
@@ -56,7 +64,7 @@ struct sysfs_dirent { | |||
56 | unsigned int s_flags; | 64 | unsigned int s_flags; |
57 | ino_t s_ino; | 65 | ino_t s_ino; |
58 | umode_t s_mode; | 66 | umode_t s_mode; |
59 | struct iattr *s_iattr; | 67 | struct sysfs_inode_attrs *s_iattr; |
60 | }; | 68 | }; |
61 | 69 | ||
62 | #define SD_DEACTIVATED_BIAS INT_MIN | 70 | #define SD_DEACTIVATED_BIAS INT_MIN |
@@ -148,6 +156,8 @@ static inline void __sysfs_put(struct sysfs_dirent *sd) | |||
148 | struct inode *sysfs_get_inode(struct sysfs_dirent *sd); | 156 | struct inode *sysfs_get_inode(struct sysfs_dirent *sd); |
149 | void sysfs_delete_inode(struct inode *inode); | 157 | void sysfs_delete_inode(struct inode *inode); |
150 | int sysfs_setattr(struct dentry *dentry, struct iattr *iattr); | 158 | int sysfs_setattr(struct dentry *dentry, struct iattr *iattr); |
159 | int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value, | ||
160 | size_t size, int flags); | ||
151 | int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name); | 161 | int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name); |
152 | int sysfs_inode_init(void); | 162 | int sysfs_inode_init(void); |
153 | 163 | ||