diff options
Diffstat (limited to 'fs/attr.c')
-rw-r--r-- | fs/attr.c | 26 |
1 files changed, 16 insertions, 10 deletions
@@ -103,12 +103,11 @@ EXPORT_SYMBOL(inode_setattr); | |||
103 | int notify_change(struct dentry * dentry, struct iattr * attr) | 103 | int notify_change(struct dentry * dentry, struct iattr * attr) |
104 | { | 104 | { |
105 | struct inode *inode = dentry->d_inode; | 105 | struct inode *inode = dentry->d_inode; |
106 | mode_t mode; | 106 | mode_t mode = inode->i_mode; |
107 | int error; | 107 | int error; |
108 | struct timespec now; | 108 | struct timespec now; |
109 | unsigned int ia_valid = attr->ia_valid; | 109 | unsigned int ia_valid = attr->ia_valid; |
110 | 110 | ||
111 | mode = inode->i_mode; | ||
112 | now = current_fs_time(inode->i_sb); | 111 | now = current_fs_time(inode->i_sb); |
113 | 112 | ||
114 | attr->ia_ctime = now; | 113 | attr->ia_ctime = now; |
@@ -125,18 +124,25 @@ int notify_change(struct dentry * dentry, struct iattr * attr) | |||
125 | if (error) | 124 | if (error) |
126 | return error; | 125 | return error; |
127 | } | 126 | } |
127 | |||
128 | /* | ||
129 | * We now pass ATTR_KILL_S*ID to the lower level setattr function so | ||
130 | * that the function has the ability to reinterpret a mode change | ||
131 | * that's due to these bits. This adds an implicit restriction that | ||
132 | * no function will ever call notify_change with both ATTR_MODE and | ||
133 | * ATTR_KILL_S*ID set. | ||
134 | */ | ||
135 | if ((ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID)) && | ||
136 | (ia_valid & ATTR_MODE)) | ||
137 | BUG(); | ||
138 | |||
128 | if (ia_valid & ATTR_KILL_SUID) { | 139 | if (ia_valid & ATTR_KILL_SUID) { |
129 | attr->ia_valid &= ~ATTR_KILL_SUID; | ||
130 | if (mode & S_ISUID) { | 140 | if (mode & S_ISUID) { |
131 | if (!(ia_valid & ATTR_MODE)) { | 141 | ia_valid = attr->ia_valid |= ATTR_MODE; |
132 | ia_valid = attr->ia_valid |= ATTR_MODE; | 142 | attr->ia_mode = (inode->i_mode & ~S_ISUID); |
133 | attr->ia_mode = inode->i_mode; | ||
134 | } | ||
135 | attr->ia_mode &= ~S_ISUID; | ||
136 | } | 143 | } |
137 | } | 144 | } |
138 | if (ia_valid & ATTR_KILL_SGID) { | 145 | if (ia_valid & ATTR_KILL_SGID) { |
139 | attr->ia_valid &= ~ ATTR_KILL_SGID; | ||
140 | if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { | 146 | if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { |
141 | if (!(ia_valid & ATTR_MODE)) { | 147 | if (!(ia_valid & ATTR_MODE)) { |
142 | ia_valid = attr->ia_valid |= ATTR_MODE; | 148 | ia_valid = attr->ia_valid |= ATTR_MODE; |
@@ -145,7 +151,7 @@ int notify_change(struct dentry * dentry, struct iattr * attr) | |||
145 | attr->ia_mode &= ~S_ISGID; | 151 | attr->ia_mode &= ~S_ISGID; |
146 | } | 152 | } |
147 | } | 153 | } |
148 | if (!attr->ia_valid) | 154 | if (!(attr->ia_valid & ~(ATTR_KILL_SUID | ATTR_KILL_SGID))) |
149 | return 0; | 155 | return 0; |
150 | 156 | ||
151 | if (ia_valid & ATTR_SIZE) | 157 | if (ia_valid & ATTR_SIZE) |