diff options
Diffstat (limited to 'fs')
| -rw-r--r-- | fs/locks.c | 2 | ||||
| -rw-r--r-- | fs/namei.c | 6 | ||||
| -rw-r--r-- | fs/nfsd/auth.c | 4 | ||||
| -rw-r--r-- | fs/nfsd/nfssvc.c | 2 | ||||
| -rw-r--r-- | fs/nfsd/vfs.c | 3 | ||||
| -rw-r--r-- | fs/open.c | 12 | ||||
| -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 | ||||
| -rw-r--r-- | fs/xattr.c | 55 |
11 files changed, 176 insertions, 57 deletions
diff --git a/fs/locks.c b/fs/locks.c index b6440f52178f..52366e877d76 100644 --- a/fs/locks.c +++ b/fs/locks.c | |||
| @@ -1591,7 +1591,7 @@ SYSCALL_DEFINE2(flock, unsigned int, fd, unsigned int, cmd) | |||
| 1591 | if (can_sleep) | 1591 | if (can_sleep) |
| 1592 | lock->fl_flags |= FL_SLEEP; | 1592 | lock->fl_flags |= FL_SLEEP; |
| 1593 | 1593 | ||
| 1594 | error = security_file_lock(filp, cmd); | 1594 | error = security_file_lock(filp, lock->fl_type); |
| 1595 | if (error) | 1595 | if (error) |
| 1596 | goto out_free; | 1596 | goto out_free; |
| 1597 | 1597 | ||
diff --git a/fs/namei.c b/fs/namei.c index ed27bb205b7e..d11f404667e9 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
| @@ -1533,9 +1533,11 @@ int may_open(struct path *path, int acc_mode, int flag) | |||
| 1533 | if (error) | 1533 | if (error) |
| 1534 | return error; | 1534 | return error; |
| 1535 | 1535 | ||
| 1536 | error = ima_path_check(path, | 1536 | error = ima_path_check(path, acc_mode ? |
| 1537 | acc_mode & (MAY_READ | MAY_WRITE | MAY_EXEC), | 1537 | acc_mode & (MAY_READ | MAY_WRITE | MAY_EXEC) : |
| 1538 | ACC_MODE(flag) & (MAY_READ | MAY_WRITE), | ||
| 1538 | IMA_COUNT_UPDATE); | 1539 | IMA_COUNT_UPDATE); |
| 1540 | |||
| 1539 | if (error) | 1541 | if (error) |
| 1540 | return error; | 1542 | return error; |
| 1541 | /* | 1543 | /* |
diff --git a/fs/nfsd/auth.c b/fs/nfsd/auth.c index 5573508f707f..36fcabbf5186 100644 --- a/fs/nfsd/auth.c +++ b/fs/nfsd/auth.c | |||
| @@ -34,6 +34,8 @@ int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp) | |||
| 34 | int flags = nfsexp_flags(rqstp, exp); | 34 | int flags = nfsexp_flags(rqstp, exp); |
| 35 | int ret; | 35 | int ret; |
| 36 | 36 | ||
| 37 | validate_process_creds(); | ||
| 38 | |||
| 37 | /* discard any old override before preparing the new set */ | 39 | /* discard any old override before preparing the new set */ |
| 38 | revert_creds(get_cred(current->real_cred)); | 40 | revert_creds(get_cred(current->real_cred)); |
| 39 | new = prepare_creds(); | 41 | new = prepare_creds(); |
| @@ -86,8 +88,10 @@ int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp) | |||
| 86 | else | 88 | else |
| 87 | new->cap_effective = cap_raise_nfsd_set(new->cap_effective, | 89 | new->cap_effective = cap_raise_nfsd_set(new->cap_effective, |
| 88 | new->cap_permitted); | 90 | new->cap_permitted); |
| 91 | validate_process_creds(); | ||
| 89 | put_cred(override_creds(new)); | 92 | put_cred(override_creds(new)); |
| 90 | put_cred(new); | 93 | put_cred(new); |
| 94 | validate_process_creds(); | ||
| 91 | return 0; | 95 | return 0; |
| 92 | 96 | ||
| 93 | oom: | 97 | oom: |
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 492c79b7800b..24d58adfe5fd 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c | |||
| @@ -496,7 +496,9 @@ nfsd(void *vrqstp) | |||
| 496 | /* Lock the export hash tables for reading. */ | 496 | /* Lock the export hash tables for reading. */ |
| 497 | exp_readlock(); | 497 | exp_readlock(); |
| 498 | 498 | ||
| 499 | validate_process_creds(); | ||
| 499 | svc_process(rqstp); | 500 | svc_process(rqstp); |
| 501 | validate_process_creds(); | ||
| 500 | 502 | ||
| 501 | /* Unlock export hash tables */ | 503 | /* Unlock export hash tables */ |
| 502 | exp_readunlock(); | 504 | exp_readunlock(); |
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 23341c1063bc..8fa09bfbcba7 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
| @@ -684,6 +684,8 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, | |||
| 684 | __be32 err; | 684 | __be32 err; |
| 685 | int host_err; | 685 | int host_err; |
| 686 | 686 | ||
| 687 | validate_process_creds(); | ||
| 688 | |||
| 687 | /* | 689 | /* |
| 688 | * If we get here, then the client has already done an "open", | 690 | * If we get here, then the client has already done an "open", |
| 689 | * and (hopefully) checked permission - so allow OWNER_OVERRIDE | 691 | * and (hopefully) checked permission - so allow OWNER_OVERRIDE |
| @@ -740,6 +742,7 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, | |||
| 740 | out_nfserr: | 742 | out_nfserr: |
| 741 | err = nfserrno(host_err); | 743 | err = nfserrno(host_err); |
| 742 | out: | 744 | out: |
| 745 | validate_process_creds(); | ||
| 743 | return err; | 746 | return err; |
| 744 | } | 747 | } |
| 745 | 748 | ||
| @@ -199,7 +199,7 @@ out: | |||
| 199 | int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs, | 199 | int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs, |
| 200 | struct file *filp) | 200 | struct file *filp) |
| 201 | { | 201 | { |
| 202 | int err; | 202 | int ret; |
| 203 | struct iattr newattrs; | 203 | struct iattr newattrs; |
| 204 | 204 | ||
| 205 | /* Not pretty: "inode->i_size" shouldn't really be signed. But it is. */ | 205 | /* Not pretty: "inode->i_size" shouldn't really be signed. But it is. */ |
| @@ -214,12 +214,14 @@ int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs, | |||
| 214 | } | 214 | } |
| 215 | 215 | ||
| 216 | /* Remove suid/sgid on truncate too */ | 216 | /* Remove suid/sgid on truncate too */ |
| 217 | newattrs.ia_valid |= should_remove_suid(dentry); | 217 | ret = should_remove_suid(dentry); |
| 218 | if (ret) | ||
| 219 | newattrs.ia_valid |= ret | ATTR_FORCE; | ||
| 218 | 220 | ||
| 219 | mutex_lock(&dentry->d_inode->i_mutex); | 221 | mutex_lock(&dentry->d_inode->i_mutex); |
| 220 | err = notify_change(dentry, &newattrs); | 222 | ret = notify_change(dentry, &newattrs); |
| 221 | mutex_unlock(&dentry->d_inode->i_mutex); | 223 | mutex_unlock(&dentry->d_inode->i_mutex); |
| 222 | return err; | 224 | return ret; |
| 223 | } | 225 | } |
| 224 | 226 | ||
| 225 | static long do_sys_truncate(const char __user *pathname, loff_t length) | 227 | static long do_sys_truncate(const char __user *pathname, loff_t length) |
| @@ -957,6 +959,8 @@ struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags, | |||
| 957 | int error; | 959 | int error; |
| 958 | struct file *f; | 960 | struct file *f; |
| 959 | 961 | ||
| 962 | validate_creds(cred); | ||
| 963 | |||
| 960 | /* | 964 | /* |
| 961 | * We must always pass in a valid mount pointer. Historically | 965 | * We must always pass in a valid mount pointer. Historically |
| 962 | * callers got away with not passing it, but we must enforce this at | 966 | * callers got away with not passing it, but we must enforce this at |
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 | ||
diff --git a/fs/xattr.c b/fs/xattr.c index 1c3d0af59ddf..6d4f6d3449fb 100644 --- a/fs/xattr.c +++ b/fs/xattr.c | |||
| @@ -66,22 +66,28 @@ xattr_permission(struct inode *inode, const char *name, int mask) | |||
| 66 | return inode_permission(inode, mask); | 66 | return inode_permission(inode, mask); |
| 67 | } | 67 | } |
| 68 | 68 | ||
| 69 | int | 69 | /** |
| 70 | vfs_setxattr(struct dentry *dentry, const char *name, const void *value, | 70 | * __vfs_setxattr_noperm - perform setxattr operation without performing |
| 71 | size_t size, int flags) | 71 | * permission checks. |
| 72 | * | ||
| 73 | * @dentry - object to perform setxattr on | ||
| 74 | * @name - xattr name to set | ||
| 75 | * @value - value to set @name to | ||
| 76 | * @size - size of @value | ||
| 77 | * @flags - flags to pass into filesystem operations | ||
| 78 | * | ||
| 79 | * returns the result of the internal setxattr or setsecurity operations. | ||
| 80 | * | ||
| 81 | * This function requires the caller to lock the inode's i_mutex before it | ||
| 82 | * is executed. It also assumes that the caller will make the appropriate | ||
| 83 | * permission checks. | ||
| 84 | */ | ||
| 85 | int __vfs_setxattr_noperm(struct dentry *dentry, const char *name, | ||
| 86 | const void *value, size_t size, int flags) | ||
| 72 | { | 87 | { |
| 73 | struct inode *inode = dentry->d_inode; | 88 | struct inode *inode = dentry->d_inode; |
| 74 | int error; | 89 | int error = -EOPNOTSUPP; |
| 75 | |||
| 76 | error = xattr_permission(inode, name, MAY_WRITE); | ||
| 77 | if (error) | ||
| 78 | return error; | ||
| 79 | 90 | ||
| 80 | mutex_lock(&inode->i_mutex); | ||
| 81 | error = security_inode_setxattr(dentry, name, value, size, flags); | ||
| 82 | if (error) | ||
| 83 | goto out; | ||
| 84 | error = -EOPNOTSUPP; | ||
| 85 | if (inode->i_op->setxattr) { | 91 | if (inode->i_op->setxattr) { |
| 86 | error = inode->i_op->setxattr(dentry, name, value, size, flags); | 92 | error = inode->i_op->setxattr(dentry, name, value, size, flags); |
| 87 | if (!error) { | 93 | if (!error) { |
| @@ -97,6 +103,29 @@ vfs_setxattr(struct dentry *dentry, const char *name, const void *value, | |||
| 97 | if (!error) | 103 | if (!error) |
| 98 | fsnotify_xattr(dentry); | 104 | fsnotify_xattr(dentry); |
| 99 | } | 105 | } |
| 106 | |||
| 107 | return error; | ||
| 108 | } | ||
| 109 | |||
| 110 | |||
| 111 | int | ||
| 112 | vfs_setxattr(struct dentry *dentry, const char *name, const void *value, | ||
| 113 | size_t size, int flags) | ||
| 114 | { | ||
| 115 | struct inode *inode = dentry->d_inode; | ||
| 116 | int error; | ||
| 117 | |||
| 118 | error = xattr_permission(inode, name, MAY_WRITE); | ||
| 119 | if (error) | ||
| 120 | return error; | ||
| 121 | |||
| 122 | mutex_lock(&inode->i_mutex); | ||
| 123 | error = security_inode_setxattr(dentry, name, value, size, flags); | ||
| 124 | if (error) | ||
| 125 | goto out; | ||
| 126 | |||
| 127 | error = __vfs_setxattr_noperm(dentry, name, value, size, flags); | ||
| 128 | |||
| 100 | out: | 129 | out: |
| 101 | mutex_unlock(&inode->i_mutex); | 130 | mutex_unlock(&inode->i_mutex); |
| 102 | return error; | 131 | return error; |
