aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/sysfs/dir.c1
-rw-r--r--fs/sysfs/inode.c134
-rw-r--r--fs/sysfs/symlink.c2
-rw-r--r--fs/sysfs/sysfs.h12
-rw-r--r--security/selinux/hooks.c5
-rw-r--r--security/smack/smack_lsm.c1
6 files changed, 118 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,
760const struct inode_operations sysfs_dir_inode_operations = { 760const 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
765static void remove_dir(struct sysfs_dirent *sd) 766static void remove_dir(struct sysfs_dirent *sd)
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
23extern struct super_block * sysfs_sb; 25extern struct super_block * sysfs_sb;
@@ -35,6 +37,7 @@ static struct backing_dev_info sysfs_backing_dev_info = {
35 37
36static const struct inode_operations sysfs_inode_operations ={ 38static const struct inode_operations sysfs_inode_operations ={
37 .setattr = sysfs_setattr, 39 .setattr = sysfs_setattr,
40 .setxattr = sysfs_setxattr,
38}; 41};
39 42
40int __init sysfs_inode_init(void) 43int __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
48struct 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}
45int sysfs_setattr(struct dentry * dentry, struct iattr * iattr) 66int 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 */ 124int 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;
160out:
104 return error; 161 return error;
105} 162}
106 163
@@ -146,6 +203,7 @@ static int sysfs_count_nlink(struct sysfs_dirent *sd)
146static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode) 203static 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:
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
211const struct inode_operations sysfs_symlink_inode_operations = { 212const 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
11struct sysfs_open_dirent; 13struct 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
36struct 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)
148struct inode *sysfs_get_inode(struct sysfs_dirent *sd); 156struct inode *sysfs_get_inode(struct sysfs_dirent *sd);
149void sysfs_delete_inode(struct inode *inode); 157void sysfs_delete_inode(struct inode *inode);
150int sysfs_setattr(struct dentry *dentry, struct iattr *iattr); 158int sysfs_setattr(struct dentry *dentry, struct iattr *iattr);
159int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value,
160 size_t size, int flags);
151int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name); 161int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name);
152int sysfs_inode_init(void); 162int sysfs_inode_init(void);
153 163
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 7118be2a74a5..417f7c994522 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -448,6 +448,10 @@ static int sb_finish_set_opts(struct super_block *sb)
448 sbsec->behavior > ARRAY_SIZE(labeling_behaviors)) 448 sbsec->behavior > ARRAY_SIZE(labeling_behaviors))
449 sbsec->flags &= ~SE_SBLABELSUPP; 449 sbsec->flags &= ~SE_SBLABELSUPP;
450 450
451 /* Special handling for sysfs. Is genfs but also has setxattr handler*/
452 if (strncmp(sb->s_type->name, "sysfs", sizeof("sysfs")) == 0)
453 sbsec->flags |= SE_SBLABELSUPP;
454
451 /* Initialize the root inode. */ 455 /* Initialize the root inode. */
452 rc = inode_doinit_with_dentry(root_inode, root); 456 rc = inode_doinit_with_dentry(root_inode, root);
453 457
@@ -2923,6 +2927,7 @@ static int selinux_inode_setsecurity(struct inode *inode, const char *name,
2923 return rc; 2927 return rc;
2924 2928
2925 isec->sid = newsid; 2929 isec->sid = newsid;
2930 isec->initialized = 1;
2926 return 0; 2931 return 0;
2927} 2932}
2928 2933
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 0b3bb646f90e..acae7ef4092d 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -1666,6 +1666,7 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name,
1666 1666
1667 if (strcmp(name, XATTR_SMACK_SUFFIX) == 0) { 1667 if (strcmp(name, XATTR_SMACK_SUFFIX) == 0) {
1668 nsp->smk_inode = sp; 1668 nsp->smk_inode = sp;
1669 nsp->smk_flags |= SMK_INODE_INSTANT;
1669 return 0; 1670 return 0;
1670 } 1671 }
1671 /* 1672 /*