diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2013-05-20 11:20:27 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2013-06-06 16:24:36 -0400 |
commit | ab7cb0dfab0baa63f9a1faa7441b90b07881a9c7 (patch) | |
tree | 9690f481aaeaf2d9f60b43a50f0ce22b2e69b381 | |
parent | 965e9c23de1c69a9fae2e68679027d01685530c4 (diff) |
NFSv4.1: Ensure that test_stateid and free_stateid use correct credentials
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r-- | fs/nfs/nfs4proc.c | 65 |
1 files changed, 50 insertions, 15 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index d94af83171af..e4398e8f512a 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -83,8 +83,10 @@ static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred, | |||
83 | struct nfs_fattr *fattr, struct iattr *sattr, | 83 | struct nfs_fattr *fattr, struct iattr *sattr, |
84 | struct nfs4_state *state); | 84 | struct nfs4_state *state); |
85 | #ifdef CONFIG_NFS_V4_1 | 85 | #ifdef CONFIG_NFS_V4_1 |
86 | static int nfs41_test_stateid(struct nfs_server *, nfs4_stateid *); | 86 | static int nfs41_test_stateid(struct nfs_server *, nfs4_stateid *, |
87 | static int nfs41_free_stateid(struct nfs_server *, nfs4_stateid *); | 87 | struct rpc_cred *); |
88 | static int nfs41_free_stateid(struct nfs_server *, nfs4_stateid *, | ||
89 | struct rpc_cred *); | ||
88 | #endif | 90 | #endif |
89 | /* Prevent leaks of NFSv4 errors into userland */ | 91 | /* Prevent leaks of NFSv4 errors into userland */ |
90 | static int nfs4_map_errors(int err) | 92 | static int nfs4_map_errors(int err) |
@@ -1855,18 +1857,30 @@ static void nfs41_clear_delegation_stateid(struct nfs4_state *state) | |||
1855 | { | 1857 | { |
1856 | struct nfs_server *server = NFS_SERVER(state->inode); | 1858 | struct nfs_server *server = NFS_SERVER(state->inode); |
1857 | nfs4_stateid *stateid = &state->stateid; | 1859 | nfs4_stateid *stateid = &state->stateid; |
1858 | int status; | 1860 | struct nfs_delegation *delegation; |
1861 | struct rpc_cred *cred = NULL; | ||
1862 | int status = -NFS4ERR_BAD_STATEID; | ||
1859 | 1863 | ||
1860 | /* If a state reset has been done, test_stateid is unneeded */ | 1864 | /* If a state reset has been done, test_stateid is unneeded */ |
1861 | if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0) | 1865 | if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0) |
1862 | return; | 1866 | return; |
1863 | 1867 | ||
1864 | status = nfs41_test_stateid(server, stateid); | 1868 | /* Get the delegation credential for use by test/free_stateid */ |
1869 | rcu_read_lock(); | ||
1870 | delegation = rcu_dereference(NFS_I(state->inode)->delegation); | ||
1871 | if (delegation != NULL && | ||
1872 | nfs4_stateid_match(&delegation->stateid, stateid)) { | ||
1873 | cred = get_rpccred(delegation->cred); | ||
1874 | rcu_read_unlock(); | ||
1875 | status = nfs41_test_stateid(server, stateid, cred); | ||
1876 | } else | ||
1877 | rcu_read_unlock(); | ||
1878 | |||
1865 | if (status != NFS_OK) { | 1879 | if (status != NFS_OK) { |
1866 | /* Free the stateid unless the server explicitly | 1880 | /* Free the stateid unless the server explicitly |
1867 | * informs us the stateid is unrecognized. */ | 1881 | * informs us the stateid is unrecognized. */ |
1868 | if (status != -NFS4ERR_BAD_STATEID) | 1882 | if (status != -NFS4ERR_BAD_STATEID) |
1869 | nfs41_free_stateid(server, stateid); | 1883 | nfs41_free_stateid(server, stateid, cred); |
1870 | nfs_remove_bad_delegation(state->inode); | 1884 | nfs_remove_bad_delegation(state->inode); |
1871 | 1885 | ||
1872 | write_seqlock(&state->seqlock); | 1886 | write_seqlock(&state->seqlock); |
@@ -1874,6 +1888,9 @@ static void nfs41_clear_delegation_stateid(struct nfs4_state *state) | |||
1874 | write_sequnlock(&state->seqlock); | 1888 | write_sequnlock(&state->seqlock); |
1875 | clear_bit(NFS_DELEGATED_STATE, &state->flags); | 1889 | clear_bit(NFS_DELEGATED_STATE, &state->flags); |
1876 | } | 1890 | } |
1891 | |||
1892 | if (cred != NULL) | ||
1893 | put_rpccred(cred); | ||
1877 | } | 1894 | } |
1878 | 1895 | ||
1879 | /** | 1896 | /** |
@@ -1888,6 +1905,7 @@ static int nfs41_check_open_stateid(struct nfs4_state *state) | |||
1888 | { | 1905 | { |
1889 | struct nfs_server *server = NFS_SERVER(state->inode); | 1906 | struct nfs_server *server = NFS_SERVER(state->inode); |
1890 | nfs4_stateid *stateid = &state->open_stateid; | 1907 | nfs4_stateid *stateid = &state->open_stateid; |
1908 | struct rpc_cred *cred = state->owner->so_cred; | ||
1891 | int status; | 1909 | int status; |
1892 | 1910 | ||
1893 | /* If a state reset has been done, test_stateid is unneeded */ | 1911 | /* If a state reset has been done, test_stateid is unneeded */ |
@@ -1896,12 +1914,12 @@ static int nfs41_check_open_stateid(struct nfs4_state *state) | |||
1896 | (test_bit(NFS_O_RDWR_STATE, &state->flags) == 0)) | 1914 | (test_bit(NFS_O_RDWR_STATE, &state->flags) == 0)) |
1897 | return -NFS4ERR_BAD_STATEID; | 1915 | return -NFS4ERR_BAD_STATEID; |
1898 | 1916 | ||
1899 | status = nfs41_test_stateid(server, stateid); | 1917 | status = nfs41_test_stateid(server, stateid, cred); |
1900 | if (status != NFS_OK) { | 1918 | if (status != NFS_OK) { |
1901 | /* Free the stateid unless the server explicitly | 1919 | /* Free the stateid unless the server explicitly |
1902 | * informs us the stateid is unrecognized. */ | 1920 | * informs us the stateid is unrecognized. */ |
1903 | if (status != -NFS4ERR_BAD_STATEID) | 1921 | if (status != -NFS4ERR_BAD_STATEID) |
1904 | nfs41_free_stateid(server, stateid); | 1922 | nfs41_free_stateid(server, stateid, cred); |
1905 | 1923 | ||
1906 | clear_bit(NFS_O_RDONLY_STATE, &state->flags); | 1924 | clear_bit(NFS_O_RDONLY_STATE, &state->flags); |
1907 | clear_bit(NFS_O_WRONLY_STATE, &state->flags); | 1925 | clear_bit(NFS_O_WRONLY_STATE, &state->flags); |
@@ -5056,13 +5074,18 @@ static int nfs41_check_expired_locks(struct nfs4_state *state) | |||
5056 | 5074 | ||
5057 | list_for_each_entry(lsp, &state->lock_states, ls_locks) { | 5075 | list_for_each_entry(lsp, &state->lock_states, ls_locks) { |
5058 | if (test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags)) { | 5076 | if (test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags)) { |
5059 | status = nfs41_test_stateid(server, &lsp->ls_stateid); | 5077 | struct rpc_cred *cred = lsp->ls_state->owner->so_cred; |
5078 | |||
5079 | status = nfs41_test_stateid(server, | ||
5080 | &lsp->ls_stateid, | ||
5081 | cred); | ||
5060 | if (status != NFS_OK) { | 5082 | if (status != NFS_OK) { |
5061 | /* Free the stateid unless the server | 5083 | /* Free the stateid unless the server |
5062 | * informs us the stateid is unrecognized. */ | 5084 | * informs us the stateid is unrecognized. */ |
5063 | if (status != -NFS4ERR_BAD_STATEID) | 5085 | if (status != -NFS4ERR_BAD_STATEID) |
5064 | nfs41_free_stateid(server, | 5086 | nfs41_free_stateid(server, |
5065 | &lsp->ls_stateid); | 5087 | &lsp->ls_stateid, |
5088 | cred); | ||
5066 | clear_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags); | 5089 | clear_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags); |
5067 | ret = status; | 5090 | ret = status; |
5068 | } | 5091 | } |
@@ -6737,7 +6760,9 @@ out: | |||
6737 | return err; | 6760 | return err; |
6738 | } | 6761 | } |
6739 | 6762 | ||
6740 | static int _nfs41_test_stateid(struct nfs_server *server, nfs4_stateid *stateid) | 6763 | static int _nfs41_test_stateid(struct nfs_server *server, |
6764 | nfs4_stateid *stateid, | ||
6765 | struct rpc_cred *cred) | ||
6741 | { | 6766 | { |
6742 | int status; | 6767 | int status; |
6743 | struct nfs41_test_stateid_args args = { | 6768 | struct nfs41_test_stateid_args args = { |
@@ -6748,6 +6773,7 @@ static int _nfs41_test_stateid(struct nfs_server *server, nfs4_stateid *stateid) | |||
6748 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_TEST_STATEID], | 6773 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_TEST_STATEID], |
6749 | .rpc_argp = &args, | 6774 | .rpc_argp = &args, |
6750 | .rpc_resp = &res, | 6775 | .rpc_resp = &res, |
6776 | .rpc_cred = cred, | ||
6751 | }; | 6777 | }; |
6752 | 6778 | ||
6753 | dprintk("NFS call test_stateid %p\n", stateid); | 6779 | dprintk("NFS call test_stateid %p\n", stateid); |
@@ -6768,17 +6794,20 @@ static int _nfs41_test_stateid(struct nfs_server *server, nfs4_stateid *stateid) | |||
6768 | * | 6794 | * |
6769 | * @server: server / transport on which to perform the operation | 6795 | * @server: server / transport on which to perform the operation |
6770 | * @stateid: state ID to test | 6796 | * @stateid: state ID to test |
6797 | * @cred: credential | ||
6771 | * | 6798 | * |
6772 | * Returns NFS_OK if the server recognizes that "stateid" is valid. | 6799 | * Returns NFS_OK if the server recognizes that "stateid" is valid. |
6773 | * Otherwise a negative NFS4ERR value is returned if the operation | 6800 | * Otherwise a negative NFS4ERR value is returned if the operation |
6774 | * failed or the state ID is not currently valid. | 6801 | * failed or the state ID is not currently valid. |
6775 | */ | 6802 | */ |
6776 | static int nfs41_test_stateid(struct nfs_server *server, nfs4_stateid *stateid) | 6803 | static int nfs41_test_stateid(struct nfs_server *server, |
6804 | nfs4_stateid *stateid, | ||
6805 | struct rpc_cred *cred) | ||
6777 | { | 6806 | { |
6778 | struct nfs4_exception exception = { }; | 6807 | struct nfs4_exception exception = { }; |
6779 | int err; | 6808 | int err; |
6780 | do { | 6809 | do { |
6781 | err = _nfs41_test_stateid(server, stateid); | 6810 | err = _nfs41_test_stateid(server, stateid, cred); |
6782 | if (err != -NFS4ERR_DELAY) | 6811 | if (err != -NFS4ERR_DELAY) |
6783 | break; | 6812 | break; |
6784 | nfs4_handle_exception(server, err, &exception); | 6813 | nfs4_handle_exception(server, err, &exception); |
@@ -6827,10 +6856,12 @@ const struct rpc_call_ops nfs41_free_stateid_ops = { | |||
6827 | 6856 | ||
6828 | static struct rpc_task *_nfs41_free_stateid(struct nfs_server *server, | 6857 | static struct rpc_task *_nfs41_free_stateid(struct nfs_server *server, |
6829 | nfs4_stateid *stateid, | 6858 | nfs4_stateid *stateid, |
6859 | struct rpc_cred *cred, | ||
6830 | bool privileged) | 6860 | bool privileged) |
6831 | { | 6861 | { |
6832 | struct rpc_message msg = { | 6862 | struct rpc_message msg = { |
6833 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FREE_STATEID], | 6863 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FREE_STATEID], |
6864 | .rpc_cred = cred, | ||
6834 | }; | 6865 | }; |
6835 | struct rpc_task_setup task_setup = { | 6866 | struct rpc_task_setup task_setup = { |
6836 | .rpc_client = server->client, | 6867 | .rpc_client = server->client, |
@@ -6863,16 +6894,19 @@ static struct rpc_task *_nfs41_free_stateid(struct nfs_server *server, | |||
6863 | * | 6894 | * |
6864 | * @server: server / transport on which to perform the operation | 6895 | * @server: server / transport on which to perform the operation |
6865 | * @stateid: state ID to release | 6896 | * @stateid: state ID to release |
6897 | * @cred: credential | ||
6866 | * | 6898 | * |
6867 | * Returns NFS_OK if the server freed "stateid". Otherwise a | 6899 | * Returns NFS_OK if the server freed "stateid". Otherwise a |
6868 | * negative NFS4ERR value is returned. | 6900 | * negative NFS4ERR value is returned. |
6869 | */ | 6901 | */ |
6870 | static int nfs41_free_stateid(struct nfs_server *server, nfs4_stateid *stateid) | 6902 | static int nfs41_free_stateid(struct nfs_server *server, |
6903 | nfs4_stateid *stateid, | ||
6904 | struct rpc_cred *cred) | ||
6871 | { | 6905 | { |
6872 | struct rpc_task *task; | 6906 | struct rpc_task *task; |
6873 | int ret; | 6907 | int ret; |
6874 | 6908 | ||
6875 | task = _nfs41_free_stateid(server, stateid, true); | 6909 | task = _nfs41_free_stateid(server, stateid, cred, true); |
6876 | if (IS_ERR(task)) | 6910 | if (IS_ERR(task)) |
6877 | return PTR_ERR(task); | 6911 | return PTR_ERR(task); |
6878 | ret = rpc_wait_for_completion_task(task); | 6912 | ret = rpc_wait_for_completion_task(task); |
@@ -6885,8 +6919,9 @@ static int nfs41_free_stateid(struct nfs_server *server, nfs4_stateid *stateid) | |||
6885 | static int nfs41_free_lock_state(struct nfs_server *server, struct nfs4_lock_state *lsp) | 6919 | static int nfs41_free_lock_state(struct nfs_server *server, struct nfs4_lock_state *lsp) |
6886 | { | 6920 | { |
6887 | struct rpc_task *task; | 6921 | struct rpc_task *task; |
6922 | struct rpc_cred *cred = lsp->ls_state->owner->so_cred; | ||
6888 | 6923 | ||
6889 | task = _nfs41_free_stateid(server, &lsp->ls_stateid, false); | 6924 | task = _nfs41_free_stateid(server, &lsp->ls_stateid, cred, false); |
6890 | nfs4_free_lock_state(server, lsp); | 6925 | nfs4_free_lock_state(server, lsp); |
6891 | if (IS_ERR(task)) | 6926 | if (IS_ERR(task)) |
6892 | return PTR_ERR(task); | 6927 | return PTR_ERR(task); |