Linux Headquarters
[ Register ]
[ About us ] [ Home Page ]

Advertisement
[ Kernel ] [ Documentation ] [ Links ] [ Books ]

Advertisement

Kernel v2.6.24-rc8 /fs/attr.c

Filename:/fs/attr.c
Lines Added:25
Lines Deleted:10
Also changed in: (Previous) 2.6.24-rc7  2.6.24-rc6  2.6.24-rc5  2.6.24-rc4  2.6.24-rc3  2.6.24-rc2 
(Following) 2.6.24  2.6.26-git15  2.6.26-git16  2.6.26-git17  2.6.26-git18  2.6.27-rc1 

Location
[  2.6.24-rc8
  [  fs
     o  attr.c

Patch

diff --git a/fs/attr.c b/fs/attr.c
index f8dfc22..966b73e 100644
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -103,12 +103,11 @@ EXPORT_SYMBOL(inode_setattr);
 int notify_change(struct dentry * dentry, struct iattr * attr)
 {
    struct inode *inode = dentry->d_inode;
-   mode_t mode;
+   mode_t mode = inode->i_mode;
    int error;
    struct timespec now;
    unsigned int ia_valid = attr->ia_valid;
 
-   mode = inode->i_mode;
    now = current_fs_time(inode->i_sb);
 
    attr->ia_ctime = now;
@@ -116,18 +115,34 @@ int notify_change(struct dentry * dentry, struct iattr * attr)
       attr->ia_atime = now;
    if (!(ia_valid & ATTR_MTIME_SET))
       attr->ia_mtime = now;
+   if (ia_valid & ATTR_KILL_PRIV) {
+      attr->ia_valid &= ~ATTR_KILL_PRIV;
+      ia_valid &= ~ATTR_KILL_PRIV;
+      error = security_inode_need_killpriv(dentry);
+      if (error > 0)
+         error = security_inode_killpriv(dentry);
+      if (error)
+         return error;
+   }
+
+   /*
+    * 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)) &&
+       (ia_valid & ATTR_MODE))
+      BUG();
+
    if (ia_valid & ATTR_KILL_SUID) {
-      attr->ia_valid &= ~ATTR_KILL_SUID;
       if (mode & S_ISUID) {
-         if (!(ia_valid & ATTR_MODE)) {
-            ia_valid = attr->ia_valid |= ATTR_MODE;
-            attr->ia_mode = inode->i_mode;
-         }
-         attr->ia_mode &= ~S_ISUID;
+         ia_valid = attr->ia_valid |= ATTR_MODE;
+         attr->ia_mode = (inode->i_mode & ~S_ISUID);
       }
    }
    if (ia_valid & ATTR_KILL_SGID) {
-      attr->ia_valid &= ~ ATTR_KILL_SGID;
       if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
          if (!(ia_valid & ATTR_MODE)) {
             ia_valid = attr->ia_valid |= ATTR_MODE;
@@ -136,7 +151,7 @@ int notify_change(struct dentry * dentry, struct iattr * attr)
          attr->ia_mode &= ~S_ISGID;
       }
    }
-   if (!attr->ia_valid)
+   if (!(attr->ia_valid & ~(ATTR_KILL_SUID | ATTR_KILL_SGID)))
       return 0;
 
    if (ia_valid & ATTR_SIZE)


Comments: webmaster (at) linuxhq.com.
Advertising: banners (at) linuxhq.com.
Compilation ©1998-2008 Linux Headquarters, Inc.