Good Catch Eric !
I have already installed 4.4.16 on my Production 14.2 Laptop and this bug scared me a bit when I saw it ...
Looking at your BUG dumps on kernel.org, the bug is isolated to Overlay File Systems, and may have been triggered by this change in fs/overlayfs/inode.c:
https://git.kernel.org/cgit/linux/ke...16&id2=v4.4.15
Before 4.4.16, inode->i_mode was 'anded' with S_IFMT
before writing mode into the inode structure ( mode &= S_IFMT ).
But with 4.4.16, `mode &= S_IFMT` is performed
after writing the mode into the inode structure which appears to cause the BUG() in fs/attr.c:238 ...
If I understand the code, fs/attr.c lines 240 and 246 look like a catch-22 situation when compared to the test at line 236 that caused the BUG() to be thrown.
fs/attr.c lines 229..254:
Code:
/*
* We now pass ATTR_KILL_S*ID to the lower level setattr function so
* that the function has the ability to reinterpret a mode change
* that's due to these bits. This adds an implicit restriction that
* no function will ever call notify_change with both ATTR_MODE and
* ATTR_KILL_S*ID set.
*/
if ((ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID)) && // this is line 236
(ia_valid & ATTR_MODE))
BUG(); // this is attr.c line 238
if (ia_valid & ATTR_KILL_SUID) { // this is line 240
if (mode & S_ISUID) {
ia_valid = attr->ia_valid |= ATTR_MODE;
attr->ia_mode = (inode->i_mode & ~S_ISUID);
}
}
if (ia_valid & ATTR_KILL_SGID) { // this is line 246
if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
if (!(ia_valid & ATTR_MODE)) {
ia_valid = attr->ia_valid |= ATTR_MODE;
attr->ia_mode = inode->i_mode;
}
attr->ia_mode &= ~S_ISGID;
}
}
But then again, I can't say I understand the kernel code
No worries for me since I don't use the OverlayFS on my Prod Systems but it appears that this bug will prevent adding inodes to an overlayfs for files with the SUID / SGID Bits set ...
Thanks for the report !
-- kjh
This is the change to fs/overlayfs/inode.c referenced by the above URL
Code:
diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c
index 05ac9a9..0597820 100644
--- a/fs/overlayfs/inode.c
+++ b/fs/overlayfs/inode.c
@@ -412,12 +412,11 @@ struct inode *ovl_new_inode(struct super_block *sb, umode_t mode,
if (!inode)
return NULL;
- mode &= S_IFMT;
-
inode->i_ino = get_next_ino();
inode->i_mode = mode;
inode->i_flags |= S_NOATIME | S_NOCMTIME;
+ mode &= S_IFMT;
switch (mode) {
case S_IFDIR:
inode->i_private = oe;