aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@redhat.com>2016-07-29 06:05:23 -0400
committerMiklos Szeredi <mszeredi@redhat.com>2016-07-29 06:05:23 -0400
commitbb0d2b8ad29630b580ac903f989e704e23462357 (patch)
tree906ff6b0ba636472c66510c5d1776c40bc6e7755
parent9c630ebefeeee4363ffd29f2f9b18eddafc6479c (diff)
ovl: fix sgid on directory
When creating directory in workdir, the group/sgid inheritance from the parent dir was omitted completely. Fix this by calling inode_init_owner() on overlay inode and using the resulting uid/gid/mode to create the file. Unfortunately the sgid bit can be stripped off due to umask, so need to reset the mode in this case in workdir before moving the directory in place. Reported-by: Eryu Guan <eguan@redhat.com> Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
-rw-r--r--fs/overlayfs/dir.c31
1 files changed, 27 insertions, 4 deletions
diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c
index 7195306e9f84..8beeed34dad6 100644
--- a/fs/overlayfs/dir.c
+++ b/fs/overlayfs/dir.c
@@ -357,6 +357,21 @@ static int ovl_create_over_whiteout(struct dentry *dentry, struct inode *inode,
357 if (err) 357 if (err)
358 goto out_dput2; 358 goto out_dput2;
359 359
360 /*
361 * mode could have been mutilated due to umask (e.g. sgid directory)
362 */
363 if (!S_ISLNK(stat->mode) && newdentry->d_inode->i_mode != stat->mode) {
364 struct iattr attr = {
365 .ia_valid = ATTR_MODE,
366 .ia_mode = stat->mode,
367 };
368 inode_lock(newdentry->d_inode);
369 err = notify_change(newdentry, &attr, NULL);
370 inode_unlock(newdentry->d_inode);
371 if (err)
372 goto out_cleanup;
373 }
374
360 if (S_ISDIR(stat->mode)) { 375 if (S_ISDIR(stat->mode)) {
361 err = ovl_set_opaque(newdentry); 376 err = ovl_set_opaque(newdentry);
362 if (err) 377 if (err)
@@ -397,7 +412,6 @@ static int ovl_create_or_link(struct dentry *dentry, int mode, dev_t rdev,
397 const struct cred *old_cred; 412 const struct cred *old_cred;
398 struct cred *override_cred; 413 struct cred *override_cred;
399 struct kstat stat = { 414 struct kstat stat = {
400 .mode = mode,
401 .rdev = rdev, 415 .rdev = rdev,
402 }; 416 };
403 417
@@ -410,12 +424,15 @@ static int ovl_create_or_link(struct dentry *dentry, int mode, dev_t rdev,
410 if (err) 424 if (err)
411 goto out_iput; 425 goto out_iput;
412 426
427 inode_init_owner(inode, dentry->d_parent->d_inode, mode);
428 stat.mode = inode->i_mode;
429
413 old_cred = ovl_override_creds(dentry->d_sb); 430 old_cred = ovl_override_creds(dentry->d_sb);
414 err = -ENOMEM; 431 err = -ENOMEM;
415 override_cred = prepare_creds(); 432 override_cred = prepare_creds();
416 if (override_cred) { 433 if (override_cred) {
417 override_cred->fsuid = old_cred->fsuid; 434 override_cred->fsuid = inode->i_uid;
418 override_cred->fsgid = old_cred->fsgid; 435 override_cred->fsgid = inode->i_gid;
419 put_cred(override_creds(override_cred)); 436 put_cred(override_creds(override_cred));
420 put_cred(override_cred); 437 put_cred(override_cred);
421 438
@@ -427,8 +444,14 @@ static int ovl_create_or_link(struct dentry *dentry, int mode, dev_t rdev,
427 link, hardlink); 444 link, hardlink);
428 } 445 }
429 revert_creds(old_cred); 446 revert_creds(old_cred);
430 if (!err) 447 if (!err) {
448 struct inode *realinode = d_inode(ovl_dentry_upper(dentry));
449
450 WARN_ON(inode->i_mode != realinode->i_mode);
451 WARN_ON(!uid_eq(inode->i_uid, realinode->i_uid));
452 WARN_ON(!gid_eq(inode->i_gid, realinode->i_gid));
431 inode = NULL; 453 inode = NULL;
454 }
432out_iput: 455out_iput:
433 iput(inode); 456 iput(inode);
434out: 457out: