diff options
author | Eric W. Biederman <ebiederm@xmission.com> | 2006-06-26 03:25:49 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-06-26 12:58:25 -0400 |
commit | cd6a3ce9ec040c0b56ea92a81ff710417798c559 (patch) | |
tree | 350c0b4bb63a971c9409be8459a45b690ef4ac67 /fs/proc | |
parent | 48e6484d49020dba3578ad117b461e8a391e8f0f (diff) |
[PATCH] proc: Close the race of a process dying durning lookup
proc_lookup and task exiting are not synchronized, although some of the
previous code may have suggested that. Every time before we reuse a dentry
namei.c calls d_op->derevalidate which prevents us from reusing a stale dcache
entry. Unfortunately it does not prevent us from returning a stale dcache
entry. This race has been explicitly plugged in proc_pid_lookup but there is
nothing to confine it to just that proc lookup function.
So to prevent the race I call revalidate explictily in all of the proc lookup
functions after I call d_add, and report an error if the revalidate does not
succeed.
Years ago Al Viro did something similar but those changes got lost in the
churn.
Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs/proc')
-rw-r--r-- | fs/proc/base.c | 54 |
1 files changed, 29 insertions, 25 deletions
diff --git a/fs/proc/base.c b/fs/proc/base.c index f435932e6432..98eaeaa9fdd1 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
@@ -1402,6 +1402,7 @@ static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry, | |||
1402 | { | 1402 | { |
1403 | struct task_struct *task = proc_task(dir); | 1403 | struct task_struct *task = proc_task(dir); |
1404 | unsigned fd = name_to_int(dentry); | 1404 | unsigned fd = name_to_int(dentry); |
1405 | struct dentry *result = ERR_PTR(-ENOENT); | ||
1405 | struct file * file; | 1406 | struct file * file; |
1406 | struct files_struct * files; | 1407 | struct files_struct * files; |
1407 | struct inode *inode; | 1408 | struct inode *inode; |
@@ -1441,15 +1442,18 @@ static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry, | |||
1441 | ei->op.proc_get_link = proc_fd_link; | 1442 | ei->op.proc_get_link = proc_fd_link; |
1442 | dentry->d_op = &tid_fd_dentry_operations; | 1443 | dentry->d_op = &tid_fd_dentry_operations; |
1443 | d_add(dentry, inode); | 1444 | d_add(dentry, inode); |
1444 | return NULL; | 1445 | /* Close the race of the process dying before we return the dentry */ |
1446 | if (tid_fd_revalidate(dentry, NULL)) | ||
1447 | result = NULL; | ||
1448 | out: | ||
1449 | return result; | ||
1445 | 1450 | ||
1446 | out_unlock2: | 1451 | out_unlock2: |
1447 | spin_unlock(&files->file_lock); | 1452 | spin_unlock(&files->file_lock); |
1448 | put_files_struct(files); | 1453 | put_files_struct(files); |
1449 | out_unlock: | 1454 | out_unlock: |
1450 | iput(inode); | 1455 | iput(inode); |
1451 | out: | 1456 | goto out; |
1452 | return ERR_PTR(-ENOENT); | ||
1453 | } | 1457 | } |
1454 | 1458 | ||
1455 | static int proc_task_readdir(struct file * filp, void * dirent, filldir_t filldir); | 1459 | static int proc_task_readdir(struct file * filp, void * dirent, filldir_t filldir); |
@@ -1549,12 +1553,12 @@ static struct dentry *proc_pident_lookup(struct inode *dir, | |||
1549 | struct pid_entry *ents) | 1553 | struct pid_entry *ents) |
1550 | { | 1554 | { |
1551 | struct inode *inode; | 1555 | struct inode *inode; |
1552 | int error; | 1556 | struct dentry *error; |
1553 | struct task_struct *task = proc_task(dir); | 1557 | struct task_struct *task = proc_task(dir); |
1554 | struct pid_entry *p; | 1558 | struct pid_entry *p; |
1555 | struct proc_inode *ei; | 1559 | struct proc_inode *ei; |
1556 | 1560 | ||
1557 | error = -ENOENT; | 1561 | error = ERR_PTR(-ENOENT); |
1558 | inode = NULL; | 1562 | inode = NULL; |
1559 | 1563 | ||
1560 | if (!pid_alive(task)) | 1564 | if (!pid_alive(task)) |
@@ -1569,7 +1573,7 @@ static struct dentry *proc_pident_lookup(struct inode *dir, | |||
1569 | if (!p->name) | 1573 | if (!p->name) |
1570 | goto out; | 1574 | goto out; |
1571 | 1575 | ||
1572 | error = -EINVAL; | 1576 | error = ERR_PTR(-EINVAL); |
1573 | inode = proc_pid_make_inode(dir->i_sb, task, p->type); | 1577 | inode = proc_pid_make_inode(dir->i_sb, task, p->type); |
1574 | if (!inode) | 1578 | if (!inode) |
1575 | goto out; | 1579 | goto out; |
@@ -1736,14 +1740,16 @@ static struct dentry *proc_pident_lookup(struct inode *dir, | |||
1736 | default: | 1740 | default: |
1737 | printk("procfs: impossible type (%d)",p->type); | 1741 | printk("procfs: impossible type (%d)",p->type); |
1738 | iput(inode); | 1742 | iput(inode); |
1739 | return ERR_PTR(-EINVAL); | 1743 | error = ERR_PTR(-EINVAL); |
1744 | goto out; | ||
1740 | } | 1745 | } |
1741 | dentry->d_op = &pid_dentry_operations; | 1746 | dentry->d_op = &pid_dentry_operations; |
1742 | d_add(dentry, inode); | 1747 | d_add(dentry, inode); |
1743 | return NULL; | 1748 | /* Close the race of the process dying before we return the dentry */ |
1744 | 1749 | if (pid_revalidate(dentry, NULL)) | |
1750 | error = NULL; | ||
1745 | out: | 1751 | out: |
1746 | return ERR_PTR(error); | 1752 | return error; |
1747 | } | 1753 | } |
1748 | 1754 | ||
1749 | static struct dentry *proc_tgid_base_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd){ | 1755 | static struct dentry *proc_tgid_base_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd){ |
@@ -1911,6 +1917,7 @@ out: | |||
1911 | /* SMP-safe */ | 1917 | /* SMP-safe */ |
1912 | struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd) | 1918 | struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd) |
1913 | { | 1919 | { |
1920 | struct dentry *result = ERR_PTR(-ENOENT); | ||
1914 | struct task_struct *task; | 1921 | struct task_struct *task; |
1915 | struct inode *inode; | 1922 | struct inode *inode; |
1916 | struct proc_inode *ei; | 1923 | struct proc_inode *ei; |
@@ -1944,12 +1951,9 @@ struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct | |||
1944 | goto out; | 1951 | goto out; |
1945 | 1952 | ||
1946 | inode = proc_pid_make_inode(dir->i_sb, task, PROC_TGID_INO); | 1953 | inode = proc_pid_make_inode(dir->i_sb, task, PROC_TGID_INO); |
1954 | if (!inode) | ||
1955 | goto out_put_task; | ||
1947 | 1956 | ||
1948 | |||
1949 | if (!inode) { | ||
1950 | put_task_struct(task); | ||
1951 | goto out; | ||
1952 | } | ||
1953 | inode->i_mode = S_IFDIR|S_IRUGO|S_IXUGO; | 1957 | inode->i_mode = S_IFDIR|S_IRUGO|S_IXUGO; |
1954 | inode->i_op = &proc_tgid_base_inode_operations; | 1958 | inode->i_op = &proc_tgid_base_inode_operations; |
1955 | inode->i_fop = &proc_tgid_base_operations; | 1959 | inode->i_fop = &proc_tgid_base_operations; |
@@ -1963,21 +1967,20 @@ struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct | |||
1963 | dentry->d_op = &pid_dentry_operations; | 1967 | dentry->d_op = &pid_dentry_operations; |
1964 | 1968 | ||
1965 | d_add(dentry, inode); | 1969 | d_add(dentry, inode); |
1966 | if (!pid_alive(task)) { | 1970 | /* Close the race of the process dying before we return the dentry */ |
1967 | d_drop(dentry); | 1971 | if (pid_revalidate(dentry, NULL)) |
1968 | shrink_dcache_parent(dentry); | 1972 | result = NULL; |
1969 | goto out; | ||
1970 | } | ||
1971 | 1973 | ||
1974 | out_put_task: | ||
1972 | put_task_struct(task); | 1975 | put_task_struct(task); |
1973 | return NULL; | ||
1974 | out: | 1976 | out: |
1975 | return ERR_PTR(-ENOENT); | 1977 | return result; |
1976 | } | 1978 | } |
1977 | 1979 | ||
1978 | /* SMP-safe */ | 1980 | /* SMP-safe */ |
1979 | static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd) | 1981 | static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd) |
1980 | { | 1982 | { |
1983 | struct dentry *result = ERR_PTR(-ENOENT); | ||
1981 | struct task_struct *task; | 1984 | struct task_struct *task; |
1982 | struct task_struct *leader = proc_task(dir); | 1985 | struct task_struct *leader = proc_task(dir); |
1983 | struct inode *inode; | 1986 | struct inode *inode; |
@@ -2015,13 +2018,14 @@ static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry | |||
2015 | dentry->d_op = &pid_dentry_operations; | 2018 | dentry->d_op = &pid_dentry_operations; |
2016 | 2019 | ||
2017 | d_add(dentry, inode); | 2020 | d_add(dentry, inode); |
2021 | /* Close the race of the process dying before we return the dentry */ | ||
2022 | if (pid_revalidate(dentry, NULL)) | ||
2023 | result = NULL; | ||
2018 | 2024 | ||
2019 | put_task_struct(task); | ||
2020 | return NULL; | ||
2021 | out_drop_task: | 2025 | out_drop_task: |
2022 | put_task_struct(task); | 2026 | put_task_struct(task); |
2023 | out: | 2027 | out: |
2024 | return ERR_PTR(-ENOENT); | 2028 | return result; |
2025 | } | 2029 | } |
2026 | 2030 | ||
2027 | #define PROC_NUMBUF 10 | 2031 | #define PROC_NUMBUF 10 |