aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@redhat.com>2017-07-20 05:08:21 -0400
committerMiklos Szeredi <mszeredi@redhat.com>2017-07-20 05:08:21 -0400
commit1d88f183734c0d916428911df006e645a6162cab (patch)
treedec3cc4ead42891e7f52418ddb939a2d4c359d71
parenta59f97ff66f0058702ed6f6e26dd8fa3c34caf62 (diff)
ovl: fix xattr get and set with selinux
inode_doinit_with_dentry() in SELinux wants to read the upper inode's xattr to get security label, and ovl_xattr_get() calls ovl_dentry_real(), which depends on dentry->d_inode, but d_inode is null and not initialized yet at this point resulting in an Oops. Fix by getting the upperdentry info from the inode directly in this case. Reported-by: Eryu Guan <eguan@redhat.com> Fixes: 09d8b586731b ("ovl: move __upperdentry to ovl_inode") Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
-rw-r--r--fs/overlayfs/inode.c32
-rw-r--r--fs/overlayfs/overlayfs.h7
-rw-r--r--fs/overlayfs/super.c8
-rw-r--r--fs/overlayfs/util.c7
4 files changed, 31 insertions, 23 deletions
diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c
index 69f4fc26ee39..5bc71642b226 100644
--- a/fs/overlayfs/inode.c
+++ b/fs/overlayfs/inode.c
@@ -202,37 +202,38 @@ bool ovl_is_private_xattr(const char *name)
202 sizeof(OVL_XATTR_PREFIX) - 1) == 0; 202 sizeof(OVL_XATTR_PREFIX) - 1) == 0;
203} 203}
204 204
205int ovl_xattr_set(struct dentry *dentry, const char *name, const void *value, 205int ovl_xattr_set(struct dentry *dentry, struct inode *inode, const char *name,
206 size_t size, int flags) 206 const void *value, size_t size, int flags)
207{ 207{
208 int err; 208 int err;
209 struct path realpath; 209 struct dentry *upperdentry = ovl_i_dentry_upper(inode);
210 enum ovl_path_type type = ovl_path_real(dentry, &realpath); 210 struct dentry *realdentry = upperdentry ?: ovl_dentry_lower(dentry);
211 const struct cred *old_cred; 211 const struct cred *old_cred;
212 212
213 err = ovl_want_write(dentry); 213 err = ovl_want_write(dentry);
214 if (err) 214 if (err)
215 goto out; 215 goto out;
216 216
217 if (!value && !OVL_TYPE_UPPER(type)) { 217 if (!value && !upperdentry) {
218 err = vfs_getxattr(realpath.dentry, name, NULL, 0); 218 err = vfs_getxattr(realdentry, name, NULL, 0);
219 if (err < 0) 219 if (err < 0)
220 goto out_drop_write; 220 goto out_drop_write;
221 } 221 }
222 222
223 err = ovl_copy_up(dentry); 223 if (!upperdentry) {
224 if (err) 224 err = ovl_copy_up(dentry);
225 goto out_drop_write; 225 if (err)
226 goto out_drop_write;
226 227
227 if (!OVL_TYPE_UPPER(type)) 228 realdentry = ovl_dentry_upper(dentry);
228 ovl_path_upper(dentry, &realpath); 229 }
229 230
230 old_cred = ovl_override_creds(dentry->d_sb); 231 old_cred = ovl_override_creds(dentry->d_sb);
231 if (value) 232 if (value)
232 err = vfs_setxattr(realpath.dentry, name, value, size, flags); 233 err = vfs_setxattr(realdentry, name, value, size, flags);
233 else { 234 else {
234 WARN_ON(flags != XATTR_REPLACE); 235 WARN_ON(flags != XATTR_REPLACE);
235 err = vfs_removexattr(realpath.dentry, name); 236 err = vfs_removexattr(realdentry, name);
236 } 237 }
237 revert_creds(old_cred); 238 revert_creds(old_cred);
238 239
@@ -242,12 +243,13 @@ out:
242 return err; 243 return err;
243} 244}
244 245
245int ovl_xattr_get(struct dentry *dentry, const char *name, 246int ovl_xattr_get(struct dentry *dentry, struct inode *inode, const char *name,
246 void *value, size_t size) 247 void *value, size_t size)
247{ 248{
248 struct dentry *realdentry = ovl_dentry_real(dentry);
249 ssize_t res; 249 ssize_t res;
250 const struct cred *old_cred; 250 const struct cred *old_cred;
251 struct dentry *realdentry =
252 ovl_i_dentry_upper(inode) ?: ovl_dentry_lower(dentry);
251 253
252 old_cred = ovl_override_creds(dentry->d_sb); 254 old_cred = ovl_override_creds(dentry->d_sb);
253 res = vfs_getxattr(realdentry, name, value, size); 255 res = vfs_getxattr(realdentry, name, value, size);
diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h
index 032120a761c4..e927a62c97ae 100644
--- a/fs/overlayfs/overlayfs.h
+++ b/fs/overlayfs/overlayfs.h
@@ -200,6 +200,7 @@ enum ovl_path_type ovl_path_real(struct dentry *dentry, struct path *path);
200struct dentry *ovl_dentry_upper(struct dentry *dentry); 200struct dentry *ovl_dentry_upper(struct dentry *dentry);
201struct dentry *ovl_dentry_lower(struct dentry *dentry); 201struct dentry *ovl_dentry_lower(struct dentry *dentry);
202struct dentry *ovl_dentry_real(struct dentry *dentry); 202struct dentry *ovl_dentry_real(struct dentry *dentry);
203struct dentry *ovl_i_dentry_upper(struct inode *inode);
203struct inode *ovl_inode_upper(struct inode *inode); 204struct inode *ovl_inode_upper(struct inode *inode);
204struct inode *ovl_inode_lower(struct inode *inode); 205struct inode *ovl_inode_lower(struct inode *inode);
205struct inode *ovl_inode_real(struct inode *inode); 206struct inode *ovl_inode_real(struct inode *inode);
@@ -271,9 +272,9 @@ int ovl_setattr(struct dentry *dentry, struct iattr *attr);
271int ovl_getattr(const struct path *path, struct kstat *stat, 272int ovl_getattr(const struct path *path, struct kstat *stat,
272 u32 request_mask, unsigned int flags); 273 u32 request_mask, unsigned int flags);
273int ovl_permission(struct inode *inode, int mask); 274int ovl_permission(struct inode *inode, int mask);
274int ovl_xattr_set(struct dentry *dentry, const char *name, const void *value, 275int ovl_xattr_set(struct dentry *dentry, struct inode *inode, const char *name,
275 size_t size, int flags); 276 const void *value, size_t size, int flags);
276int ovl_xattr_get(struct dentry *dentry, const char *name, 277int ovl_xattr_get(struct dentry *dentry, struct inode *inode, const char *name,
277 void *value, size_t size); 278 void *value, size_t size);
278ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size); 279ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size);
279struct posix_acl *ovl_get_acl(struct inode *inode, int type); 280struct posix_acl *ovl_get_acl(struct inode *inode, int type);
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
index c88493b01d8d..d86e89f97201 100644
--- a/fs/overlayfs/super.c
+++ b/fs/overlayfs/super.c
@@ -692,7 +692,7 @@ ovl_posix_acl_xattr_get(const struct xattr_handler *handler,
692 struct dentry *dentry, struct inode *inode, 692 struct dentry *dentry, struct inode *inode,
693 const char *name, void *buffer, size_t size) 693 const char *name, void *buffer, size_t size)
694{ 694{
695 return ovl_xattr_get(dentry, handler->name, buffer, size); 695 return ovl_xattr_get(dentry, inode, handler->name, buffer, size);
696} 696}
697 697
698static int __maybe_unused 698static int __maybe_unused
@@ -742,7 +742,7 @@ ovl_posix_acl_xattr_set(const struct xattr_handler *handler,
742 return err; 742 return err;
743 } 743 }
744 744
745 err = ovl_xattr_set(dentry, handler->name, value, size, flags); 745 err = ovl_xattr_set(dentry, inode, handler->name, value, size, flags);
746 if (!err) 746 if (!err)
747 ovl_copyattr(ovl_inode_real(inode), inode); 747 ovl_copyattr(ovl_inode_real(inode), inode);
748 748
@@ -772,7 +772,7 @@ static int ovl_other_xattr_get(const struct xattr_handler *handler,
772 struct dentry *dentry, struct inode *inode, 772 struct dentry *dentry, struct inode *inode,
773 const char *name, void *buffer, size_t size) 773 const char *name, void *buffer, size_t size)
774{ 774{
775 return ovl_xattr_get(dentry, name, buffer, size); 775 return ovl_xattr_get(dentry, inode, name, buffer, size);
776} 776}
777 777
778static int ovl_other_xattr_set(const struct xattr_handler *handler, 778static int ovl_other_xattr_set(const struct xattr_handler *handler,
@@ -780,7 +780,7 @@ static int ovl_other_xattr_set(const struct xattr_handler *handler,
780 const char *name, const void *value, 780 const char *name, const void *value,
781 size_t size, int flags) 781 size_t size, int flags)
782{ 782{
783 return ovl_xattr_set(dentry, name, value, size, flags); 783 return ovl_xattr_set(dentry, inode, name, value, size, flags);
784} 784}
785 785
786static const struct xattr_handler __maybe_unused 786static const struct xattr_handler __maybe_unused
diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c
index c492ba75c659..f46ad75dc96a 100644
--- a/fs/overlayfs/util.c
+++ b/fs/overlayfs/util.c
@@ -157,9 +157,14 @@ struct dentry *ovl_dentry_real(struct dentry *dentry)
157 return ovl_dentry_upper(dentry) ?: ovl_dentry_lower(dentry); 157 return ovl_dentry_upper(dentry) ?: ovl_dentry_lower(dentry);
158} 158}
159 159
160struct dentry *ovl_i_dentry_upper(struct inode *inode)
161{
162 return ovl_upperdentry_dereference(OVL_I(inode));
163}
164
160struct inode *ovl_inode_upper(struct inode *inode) 165struct inode *ovl_inode_upper(struct inode *inode)
161{ 166{
162 struct dentry *upperdentry = ovl_upperdentry_dereference(OVL_I(inode)); 167 struct dentry *upperdentry = ovl_i_dentry_upper(inode);
163 168
164 return upperdentry ? d_inode(upperdentry) : NULL; 169 return upperdentry ? d_inode(upperdentry) : NULL;
165} 170}