diff options
-rw-r--r-- | drivers/base/devtmpfs.c | 98 | ||||
-rw-r--r-- | fs/namei.c | 22 | ||||
-rw-r--r-- | include/linux/namei.h | 2 | ||||
-rw-r--r-- | kernel/audit_watch.c | 25 |
4 files changed, 65 insertions, 82 deletions
diff --git a/drivers/base/devtmpfs.c b/drivers/base/devtmpfs.c index 765c3a28077a..d91a3a0b2325 100644 --- a/drivers/base/devtmpfs.c +++ b/drivers/base/devtmpfs.c | |||
@@ -227,33 +227,24 @@ static int handle_create(const char *nodename, umode_t mode, struct device *dev) | |||
227 | 227 | ||
228 | static int dev_rmdir(const char *name) | 228 | static int dev_rmdir(const char *name) |
229 | { | 229 | { |
230 | struct nameidata nd; | 230 | struct path parent; |
231 | struct dentry *dentry; | 231 | struct dentry *dentry; |
232 | int err; | 232 | int err; |
233 | 233 | ||
234 | err = kern_path_parent(name, &nd); | 234 | dentry = kern_path_locked(name, &parent); |
235 | if (err) | 235 | if (IS_ERR(dentry)) |
236 | return err; | 236 | return PTR_ERR(dentry); |
237 | 237 | if (dentry->d_inode) { | |
238 | mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT); | 238 | if (dentry->d_inode->i_private == &thread) |
239 | dentry = lookup_one_len(nd.last.name, nd.path.dentry, nd.last.len); | 239 | err = vfs_rmdir(parent.dentry->d_inode, dentry); |
240 | if (!IS_ERR(dentry)) { | 240 | else |
241 | if (dentry->d_inode) { | 241 | err = -EPERM; |
242 | if (dentry->d_inode->i_private == &thread) | ||
243 | err = vfs_rmdir(nd.path.dentry->d_inode, | ||
244 | dentry); | ||
245 | else | ||
246 | err = -EPERM; | ||
247 | } else { | ||
248 | err = -ENOENT; | ||
249 | } | ||
250 | dput(dentry); | ||
251 | } else { | 242 | } else { |
252 | err = PTR_ERR(dentry); | 243 | err = -ENOENT; |
253 | } | 244 | } |
254 | 245 | dput(dentry); | |
255 | mutex_unlock(&nd.path.dentry->d_inode->i_mutex); | 246 | mutex_unlock(&parent.dentry->d_inode->i_mutex); |
256 | path_put(&nd.path); | 247 | path_put(&parent); |
257 | return err; | 248 | return err; |
258 | } | 249 | } |
259 | 250 | ||
@@ -305,50 +296,43 @@ static int dev_mynode(struct device *dev, struct inode *inode, struct kstat *sta | |||
305 | 296 | ||
306 | static int handle_remove(const char *nodename, struct device *dev) | 297 | static int handle_remove(const char *nodename, struct device *dev) |
307 | { | 298 | { |
308 | struct nameidata nd; | 299 | struct path parent; |
309 | struct dentry *dentry; | 300 | struct dentry *dentry; |
310 | struct kstat stat; | ||
311 | int deleted = 1; | 301 | int deleted = 1; |
312 | int err; | 302 | int err; |
313 | 303 | ||
314 | err = kern_path_parent(nodename, &nd); | 304 | dentry = kern_path_locked(nodename, &parent); |
315 | if (err) | 305 | if (IS_ERR(dentry)) |
316 | return err; | 306 | return PTR_ERR(dentry); |
317 | 307 | ||
318 | mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT); | 308 | if (dentry->d_inode) { |
319 | dentry = lookup_one_len(nd.last.name, nd.path.dentry, nd.last.len); | 309 | struct kstat stat; |
320 | if (!IS_ERR(dentry)) { | 310 | err = vfs_getattr(parent.mnt, dentry, &stat); |
321 | if (dentry->d_inode) { | 311 | if (!err && dev_mynode(dev, dentry->d_inode, &stat)) { |
322 | err = vfs_getattr(nd.path.mnt, dentry, &stat); | 312 | struct iattr newattrs; |
323 | if (!err && dev_mynode(dev, dentry->d_inode, &stat)) { | 313 | /* |
324 | struct iattr newattrs; | 314 | * before unlinking this node, reset permissions |
325 | /* | 315 | * of possible references like hardlinks |
326 | * before unlinking this node, reset permissions | 316 | */ |
327 | * of possible references like hardlinks | 317 | newattrs.ia_uid = 0; |
328 | */ | 318 | newattrs.ia_gid = 0; |
329 | newattrs.ia_uid = 0; | 319 | newattrs.ia_mode = stat.mode & ~0777; |
330 | newattrs.ia_gid = 0; | 320 | newattrs.ia_valid = |
331 | newattrs.ia_mode = stat.mode & ~0777; | 321 | ATTR_UID|ATTR_GID|ATTR_MODE; |
332 | newattrs.ia_valid = | 322 | mutex_lock(&dentry->d_inode->i_mutex); |
333 | ATTR_UID|ATTR_GID|ATTR_MODE; | 323 | notify_change(dentry, &newattrs); |
334 | mutex_lock(&dentry->d_inode->i_mutex); | 324 | mutex_unlock(&dentry->d_inode->i_mutex); |
335 | notify_change(dentry, &newattrs); | 325 | err = vfs_unlink(parent.dentry->d_inode, dentry); |
336 | mutex_unlock(&dentry->d_inode->i_mutex); | 326 | if (!err || err == -ENOENT) |
337 | err = vfs_unlink(nd.path.dentry->d_inode, | 327 | deleted = 1; |
338 | dentry); | ||
339 | if (!err || err == -ENOENT) | ||
340 | deleted = 1; | ||
341 | } | ||
342 | } else { | ||
343 | err = -ENOENT; | ||
344 | } | 328 | } |
345 | dput(dentry); | ||
346 | } else { | 329 | } else { |
347 | err = PTR_ERR(dentry); | 330 | err = -ENOENT; |
348 | } | 331 | } |
349 | mutex_unlock(&nd.path.dentry->d_inode->i_mutex); | 332 | dput(dentry); |
333 | mutex_unlock(&parent.dentry->d_inode->i_mutex); | ||
350 | 334 | ||
351 | path_put(&nd.path); | 335 | path_put(&parent); |
352 | if (deleted && strchr(nodename, '/')) | 336 | if (deleted && strchr(nodename, '/')) |
353 | delete_path(nodename); | 337 | delete_path(nodename); |
354 | return err; | 338 | return err; |
diff --git a/fs/namei.c b/fs/namei.c index 5abab9176903..6b29a51bef5d 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -1814,9 +1814,27 @@ static int do_path_lookup(int dfd, const char *name, | |||
1814 | return retval; | 1814 | return retval; |
1815 | } | 1815 | } |
1816 | 1816 | ||
1817 | int kern_path_parent(const char *name, struct nameidata *nd) | 1817 | /* does lookup, returns the object with parent locked */ |
1818 | struct dentry *kern_path_locked(const char *name, struct path *path) | ||
1818 | { | 1819 | { |
1819 | return do_path_lookup(AT_FDCWD, name, LOOKUP_PARENT, nd); | 1820 | struct nameidata nd; |
1821 | struct dentry *d; | ||
1822 | int err = do_path_lookup(AT_FDCWD, name, LOOKUP_PARENT, &nd); | ||
1823 | if (err) | ||
1824 | return ERR_PTR(err); | ||
1825 | if (nd.last_type != LAST_NORM) { | ||
1826 | path_put(&nd.path); | ||
1827 | return ERR_PTR(-EINVAL); | ||
1828 | } | ||
1829 | mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT); | ||
1830 | d = lookup_one_len(nd.last.name, nd.path.dentry, nd.last.len); | ||
1831 | if (IS_ERR(d)) { | ||
1832 | mutex_unlock(&nd.path.dentry->d_inode->i_mutex); | ||
1833 | path_put(&nd.path); | ||
1834 | return d; | ||
1835 | } | ||
1836 | *path = nd.path; | ||
1837 | return d; | ||
1820 | } | 1838 | } |
1821 | 1839 | ||
1822 | int kern_path(const char *name, unsigned int flags, struct path *path) | 1840 | int kern_path(const char *name, unsigned int flags, struct path *path) |
diff --git a/include/linux/namei.h b/include/linux/namei.h index 23d859879210..f5931489e150 100644 --- a/include/linux/namei.h +++ b/include/linux/namei.h | |||
@@ -67,7 +67,7 @@ extern int kern_path(const char *, unsigned, struct path *); | |||
67 | 67 | ||
68 | extern struct dentry *kern_path_create(int, const char *, struct path *, int); | 68 | extern struct dentry *kern_path_create(int, const char *, struct path *, int); |
69 | extern struct dentry *user_path_create(int, const char __user *, struct path *, int); | 69 | extern struct dentry *user_path_create(int, const char __user *, struct path *, int); |
70 | extern int kern_path_parent(const char *, struct nameidata *); | 70 | extern struct dentry *kern_path_locked(const char *, struct path *); |
71 | extern int vfs_path_lookup(struct dentry *, struct vfsmount *, | 71 | extern int vfs_path_lookup(struct dentry *, struct vfsmount *, |
72 | const char *, unsigned int, struct path *); | 72 | const char *, unsigned int, struct path *); |
73 | 73 | ||
diff --git a/kernel/audit_watch.c b/kernel/audit_watch.c index e683869365d9..3823281401b5 100644 --- a/kernel/audit_watch.c +++ b/kernel/audit_watch.c | |||
@@ -355,34 +355,15 @@ static void audit_remove_parent_watches(struct audit_parent *parent) | |||
355 | /* Get path information necessary for adding watches. */ | 355 | /* Get path information necessary for adding watches. */ |
356 | static int audit_get_nd(struct audit_watch *watch, struct path *parent) | 356 | static int audit_get_nd(struct audit_watch *watch, struct path *parent) |
357 | { | 357 | { |
358 | struct nameidata nd; | 358 | struct dentry *d = kern_path_locked(watch->path, parent); |
359 | struct dentry *d; | 359 | if (IS_ERR(d)) |
360 | int err; | ||
361 | |||
362 | err = kern_path_parent(watch->path, &nd); | ||
363 | if (err) | ||
364 | return err; | ||
365 | |||
366 | if (nd.last_type != LAST_NORM) { | ||
367 | path_put(&nd.path); | ||
368 | return -EINVAL; | ||
369 | } | ||
370 | |||
371 | mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT); | ||
372 | d = lookup_one_len(nd.last.name, nd.path.dentry, nd.last.len); | ||
373 | if (IS_ERR(d)) { | ||
374 | mutex_unlock(&nd.path.dentry->d_inode->i_mutex); | ||
375 | path_put(&nd.path); | ||
376 | return PTR_ERR(d); | 360 | return PTR_ERR(d); |
377 | } | 361 | mutex_unlock(&parent->dentry->d_inode->i_mutex); |
378 | if (d->d_inode) { | 362 | if (d->d_inode) { |
379 | /* update watch filter fields */ | 363 | /* update watch filter fields */ |
380 | watch->dev = d->d_inode->i_sb->s_dev; | 364 | watch->dev = d->d_inode->i_sb->s_dev; |
381 | watch->ino = d->d_inode->i_ino; | 365 | watch->ino = d->d_inode->i_ino; |
382 | } | 366 | } |
383 | mutex_unlock(&nd.path.dentry->d_inode->i_mutex); | ||
384 | |||
385 | *parent = nd.path; | ||
386 | dput(d); | 367 | dput(d); |
387 | return 0; | 368 | return 0; |
388 | } | 369 | } |