diff options
author | Miklos Szeredi <mszeredi@redhat.com> | 2017-07-20 05:08:21 -0400 |
---|---|---|
committer | Miklos Szeredi <mszeredi@redhat.com> | 2017-07-20 05:08:21 -0400 |
commit | 1d88f183734c0d916428911df006e645a6162cab (patch) | |
tree | dec3cc4ead42891e7f52418ddb939a2d4c359d71 | |
parent | a59f97ff66f0058702ed6f6e26dd8fa3c34caf62 (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.c | 32 | ||||
-rw-r--r-- | fs/overlayfs/overlayfs.h | 7 | ||||
-rw-r--r-- | fs/overlayfs/super.c | 8 | ||||
-rw-r--r-- | fs/overlayfs/util.c | 7 |
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 | ||
205 | int ovl_xattr_set(struct dentry *dentry, const char *name, const void *value, | 205 | int 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 | ||
245 | int ovl_xattr_get(struct dentry *dentry, const char *name, | 246 | int 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); | |||
200 | struct dentry *ovl_dentry_upper(struct dentry *dentry); | 200 | struct dentry *ovl_dentry_upper(struct dentry *dentry); |
201 | struct dentry *ovl_dentry_lower(struct dentry *dentry); | 201 | struct dentry *ovl_dentry_lower(struct dentry *dentry); |
202 | struct dentry *ovl_dentry_real(struct dentry *dentry); | 202 | struct dentry *ovl_dentry_real(struct dentry *dentry); |
203 | struct dentry *ovl_i_dentry_upper(struct inode *inode); | ||
203 | struct inode *ovl_inode_upper(struct inode *inode); | 204 | struct inode *ovl_inode_upper(struct inode *inode); |
204 | struct inode *ovl_inode_lower(struct inode *inode); | 205 | struct inode *ovl_inode_lower(struct inode *inode); |
205 | struct inode *ovl_inode_real(struct inode *inode); | 206 | struct inode *ovl_inode_real(struct inode *inode); |
@@ -271,9 +272,9 @@ int ovl_setattr(struct dentry *dentry, struct iattr *attr); | |||
271 | int ovl_getattr(const struct path *path, struct kstat *stat, | 272 | int ovl_getattr(const struct path *path, struct kstat *stat, |
272 | u32 request_mask, unsigned int flags); | 273 | u32 request_mask, unsigned int flags); |
273 | int ovl_permission(struct inode *inode, int mask); | 274 | int ovl_permission(struct inode *inode, int mask); |
274 | int ovl_xattr_set(struct dentry *dentry, const char *name, const void *value, | 275 | int 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); |
276 | int ovl_xattr_get(struct dentry *dentry, const char *name, | 277 | int ovl_xattr_get(struct dentry *dentry, struct inode *inode, const char *name, |
277 | void *value, size_t size); | 278 | void *value, size_t size); |
278 | ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size); | 279 | ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size); |
279 | struct posix_acl *ovl_get_acl(struct inode *inode, int type); | 280 | struct 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 | ||
698 | static int __maybe_unused | 698 | static 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 | ||
778 | static int ovl_other_xattr_set(const struct xattr_handler *handler, | 778 | static 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 | ||
786 | static const struct xattr_handler __maybe_unused | 786 | static 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 | ||
160 | struct dentry *ovl_i_dentry_upper(struct inode *inode) | ||
161 | { | ||
162 | return ovl_upperdentry_dereference(OVL_I(inode)); | ||
163 | } | ||
164 | |||
160 | struct inode *ovl_inode_upper(struct inode *inode) | 165 | struct 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 | } |