Commit 62250b3b authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman
parents 428a7e3e a969fd5a
......@@ -486,8 +486,6 @@ struct file *open_exec(const char *name)
if (!(nd.mnt->mnt_flags & MNT_NOEXEC) &&
S_ISREG(inode->i_mode)) {
int err = vfs_permission(&nd, MAY_EXEC);
if (!err && !(inode->i_mode & 0111))
err = -EACCES;
file = ERR_PTR(err);
if (!err) {
file = nameidata_to_filp(&nd, O_RDONLY);
......@@ -922,12 +920,6 @@ int prepare_binprm(struct linux_binprm *bprm)
int retval;
mode = inode->i_mode;
/*
* Check execute perms again - if the caller has CAP_DAC_OVERRIDE,
* generic_permission lets a non-executable through
*/
if (!(mode & 0111)) /* with at least _one_ execute bit set */
return -EACCES;
if (bprm->file->f_op == NULL)
return -EACCES;
......
......@@ -237,19 +237,22 @@ static int
nlm_traverse_files(struct nlm_host *host, int action)
{
struct nlm_file *file, **fp;
int i;
int i, ret = 0;
mutex_lock(&nlm_file_mutex);
for (i = 0; i < FILE_NRHASH; i++) {
fp = nlm_files + i;
while ((file = *fp) != NULL) {
file->f_count++;
mutex_unlock(&nlm_file_mutex);
/* Traverse locks, blocks and shares of this file
* and update file->f_locks count */
if (nlm_inspect_file(host, file, action)) {
mutex_unlock(&nlm_file_mutex);
return 1;
}
if (nlm_inspect_file(host, file, action))
ret = 1;
mutex_lock(&nlm_file_mutex);
file->f_count--;
/* No more references to this file. Let go of it. */
if (!file->f_blocks && !file->f_locks
&& !file->f_shares && !file->f_count) {
......@@ -262,7 +265,7 @@ nlm_traverse_files(struct nlm_host *host, int action)
}
}
mutex_unlock(&nlm_file_mutex);
return 0;
return ret;
}
/*
......
......@@ -227,10 +227,10 @@ int generic_permission(struct inode *inode, int mask,
int permission(struct inode *inode, int mask, struct nameidata *nd)
{
umode_t mode = inode->i_mode;
int retval, submask;
if (mask & MAY_WRITE) {
umode_t mode = inode->i_mode;
/*
* Nobody gets write access to a read-only fs.
......@@ -247,6 +247,13 @@ int permission(struct inode *inode, int mask, struct nameidata *nd)
}
/*
* MAY_EXEC on regular files requires special handling: We override
* filesystem execute permissions if the mode bits aren't set.
*/
if ((mask & MAY_EXEC) && S_ISREG(mode) && !(mode & S_IXUGO))
return -EACCES;
/* Ordinary permission routines do not understand MAY_APPEND. */
submask = mask & ~MAY_APPEND;
if (inode->i_op && inode->i_op->permission)
......@@ -1767,6 +1774,8 @@ struct dentry *lookup_create(struct nameidata *nd, int is_dir)
if (nd->last_type != LAST_NORM)
goto fail;
nd->flags &= ~LOOKUP_PARENT;
nd->flags |= LOOKUP_CREATE;
nd->intent.open.flags = O_EXCL;
/*
* Do the final lookup.
......
......@@ -312,7 +312,13 @@ static void nfs_invalidate_page(struct page *page, unsigned long offset)
static int nfs_release_page(struct page *page, gfp_t gfp)
{
if (gfp & __GFP_FS)
return !nfs_wb_page(page->mapping->host, page);
else
/*
* Avoid deadlock on nfs_wait_on_request().
*/
return 0;
}
const struct address_space_operations nfs_file_aops = {
......
......@@ -130,9 +130,7 @@ nfs_idmap_delete(struct nfs4_client *clp)
if (!idmap)
return;
dput(idmap->idmap_dentry);
idmap->idmap_dentry = NULL;
rpc_unlink(idmap->idmap_path);
rpc_unlink(idmap->idmap_dentry);
clp->cl_idmap = NULL;
kfree(idmap);
}
......
......@@ -2668,7 +2668,7 @@ static void nfs4_write_cached_acl(struct inode *inode, const char *buf, size_t a
nfs4_set_cached_acl(inode, acl);
}
static inline ssize_t nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t buflen)
static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t buflen)
{
struct page *pages[NFS4ACL_MAXPAGES];
struct nfs_getaclargs args = {
......@@ -2721,6 +2721,19 @@ static inline ssize_t nfs4_get_acl_uncached(struct inode *inode, void *buf, size
return ret;
}
static ssize_t nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t buflen)
{
struct nfs4_exception exception = { };
ssize_t ret;
do {
ret = __nfs4_get_acl_uncached(inode, buf, buflen);
if (ret >= 0)
break;
ret = nfs4_handle_exception(NFS_SERVER(inode), ret, &exception);
} while (exception.retry);
return ret;
}
static ssize_t nfs4_proc_get_acl(struct inode *inode, void *buf, size_t buflen)
{
struct nfs_server *server = NFS_SERVER(inode);
......@@ -2737,7 +2750,7 @@ static ssize_t nfs4_proc_get_acl(struct inode *inode, void *buf, size_t buflen)
return nfs4_get_acl_uncached(inode, buf, buflen);
}
static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen)
static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen)
{
struct nfs_server *server = NFS_SERVER(inode);
struct page *pages[NFS4ACL_MAXPAGES];
......@@ -2763,6 +2776,18 @@ static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen
return ret;
}
static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen)
{
struct nfs4_exception exception = { };
int err;
do {
err = nfs4_handle_exception(NFS_SERVER(inode),
__nfs4_proc_set_acl(inode, buf, buflen),
&exception);
} while (exception.retry);
return err;
}
static int
nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server)
{
......
......@@ -3355,7 +3355,7 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n
struct kvec *iov = rcvbuf->head;
unsigned int nr, pglen = rcvbuf->page_len;
uint32_t *end, *entry, *p, *kaddr;
uint32_t len, attrlen;
uint32_t len, attrlen, xlen;
int hdrlen, recvd, status;
status = decode_op_hdr(xdr, OP_READDIR);
......@@ -3377,10 +3377,10 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n
BUG_ON(pglen + readdir->pgbase > PAGE_CACHE_SIZE);
kaddr = p = (uint32_t *) kmap_atomic(page, KM_USER0);
end = (uint32_t *) ((char *)p + pglen + readdir->pgbase);
end = p + ((pglen + readdir->pgbase) >> 2);
entry = p;
for (nr = 0; *p++; nr++) {
if (p + 3 > end)
if (end - p < 3)
goto short_pkt;
dprintk("cookie = %Lu, ", *((unsigned long long *)p));
p += 2; /* cookie */
......@@ -3389,18 +3389,19 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n
printk(KERN_WARNING "NFS: giant filename in readdir (len 0x%x)\n", len);
goto err_unmap;
}
dprintk("filename = %*s\n", len, (char *)p);
p += XDR_QUADLEN(len);
if (p + 1 > end)
xlen = XDR_QUADLEN(len);
if (end - p < xlen + 1)
goto short_pkt;
dprintk("filename = %*s\n", len, (char *)p);
p += xlen;
len = ntohl(*p++); /* bitmap length */
p += len;
if (p + 1 > end)
if (end - p < len + 1)
goto short_pkt;
p += len;
attrlen = XDR_QUADLEN(ntohl(*p++));
p += attrlen; /* attributes */
if (p + 2 > end)
if (end - p < attrlen + 2)
goto short_pkt;
p += attrlen; /* attributes */
entry = p;
}
if (!nr && (entry[0] != 0 || entry[1] == 0))
......
......@@ -116,10 +116,17 @@ static void nfs_readpage_truncate_uninitialised_page(struct nfs_read_data *data)
pages = &data->args.pages[base >> PAGE_CACHE_SHIFT];
base &= ~PAGE_CACHE_MASK;
pglen = PAGE_CACHE_SIZE - base;
if (pglen < remainder)
memclear_highpage_flush(*pages, base, pglen);
else
for (;;) {
if (remainder <= pglen) {
memclear_highpage_flush(*pages, base, remainder);
break;
}
memclear_highpage_flush(*pages, base, pglen);
pages++;
remainder -= pglen;
pglen = PAGE_CACHE_SIZE;
base = 0;
}
}
/*
......@@ -476,6 +483,8 @@ static void nfs_readpage_set_pages_uptodate(struct nfs_read_data *data)
unsigned int base = data->args.pgbase;
struct page **pages;
if (data->res.eof)
count = data->args.count;
if (unlikely(count == 0))
return;
pages = &data->args.pages[base >> PAGE_CACHE_SHIFT];
......@@ -483,11 +492,7 @@ static void nfs_readpage_set_pages_uptodate(struct nfs_read_data *data)
count += base;
for (;count >= PAGE_CACHE_SIZE; count -= PAGE_CACHE_SIZE, pages++)
SetPageUptodate(*pages);
/*
* Was this an eof or a short read? If the latter, don't mark the page
* as uptodate yet.
*/
if (count > 0 && (data->res.eof || data->args.count == data->res.count))
if (count != 0)
SetPageUptodate(*pages);
}
......@@ -502,6 +507,8 @@ static void nfs_readpage_set_pages_error(struct nfs_read_data *data)
count += base;
for (;count >= PAGE_CACHE_SIZE; count -= PAGE_CACHE_SIZE, pages++)
SetPageError(*pages);
if (count != 0)
SetPageError(*pages);
}
/*
......
......@@ -659,7 +659,7 @@ struct nfs4_rename_res {
struct nfs4_setclientid {
const nfs4_verifier * sc_verifier; /* request */
unsigned int sc_name_len;
char sc_name[32]; /* request */
char sc_name[48]; /* request */
u32 sc_prog; /* request */
unsigned int sc_netid_len;
char sc_netid[4]; /* request */
......
......@@ -42,9 +42,9 @@ RPC_I(struct inode *inode)
extern int rpc_queue_upcall(struct inode *, struct rpc_pipe_msg *);
extern struct dentry *rpc_mkdir(char *, struct rpc_clnt *);
extern int rpc_rmdir(char *);
extern int rpc_rmdir(struct dentry *);
extern struct dentry *rpc_mkpipe(char *, void *, struct rpc_pipe_ops *, int flags);
extern int rpc_unlink(char *);
extern int rpc_unlink(struct dentry *);
extern struct vfsmount *rpc_get_mount(void);
extern void rpc_put_mount(void);
......
......@@ -37,7 +37,7 @@ extern unsigned int xprt_max_resvport;
#define RPC_MIN_RESVPORT (1U)
#define RPC_MAX_RESVPORT (65535U)
#define RPC_DEF_MIN_RESVPORT (650U)
#define RPC_DEF_MIN_RESVPORT (665U)
#define RPC_DEF_MAX_RESVPORT (1023U)
/*
......
......@@ -718,8 +718,7 @@ gss_destroy(struct rpc_auth *auth)
auth, auth->au_flavor);
gss_auth = container_of(auth, struct gss_auth, rpc_auth);
rpc_unlink(gss_auth->path);
dput(gss_auth->dentry);
rpc_unlink(gss_auth->dentry);
gss_auth->dentry = NULL;
gss_mech_put(gss_auth->mech);
......
......@@ -183,8 +183,7 @@ rpc_new_client(struct rpc_xprt *xprt, char *servname,
out_no_auth:
if (!IS_ERR(clnt->cl_dentry)) {
rpc_rmdir(clnt->cl_pathname);
dput(clnt->cl_dentry);
rpc_rmdir(clnt->cl_dentry);
rpc_put_mount();
}
out_no_path:
......@@ -251,10 +250,8 @@ rpc_clone_client(struct rpc_clnt *clnt)
new->cl_autobind = 0;
new->cl_oneshot = 0;
new->cl_dead = 0;
if (!IS_ERR(new->cl_dentry)) {
if (!IS_ERR(new->cl_dentry))
dget(new->cl_dentry);
rpc_get_mount();
}
rpc_init_rtt(&new->cl_rtt_default, clnt->cl_xprt->timeout.to_initval);
if (new->cl_auth)
atomic_inc(&new->cl_auth->au_count);
......@@ -317,11 +314,15 @@ rpc_destroy_client(struct rpc_clnt *clnt)
clnt->cl_auth = NULL;
}
if (clnt->cl_parent != clnt) {
if (!IS_ERR(clnt->cl_dentry))
dput(clnt->cl_dentry);
rpc_destroy_client(clnt->cl_parent);
goto out_free;
}
if (clnt->cl_pathname[0])
rpc_rmdir(clnt->cl_pathname);
if (!IS_ERR(clnt->cl_dentry)) {
rpc_rmdir(clnt->cl_dentry);
rpc_put_mount();
}
if (clnt->cl_xprt) {
xprt_destroy(clnt->cl_xprt);
clnt->cl_xprt = NULL;
......@@ -331,10 +332,6 @@ rpc_destroy_client(struct rpc_clnt *clnt)
out_free:
rpc_free_iostats(clnt->cl_metrics);
clnt->cl_metrics = NULL;
if (!IS_ERR(clnt->cl_dentry)) {
dput(clnt->cl_dentry);
rpc_put_mount();
}
kfree(clnt);
return 0;
}
......@@ -1184,6 +1181,17 @@ call_verify(struct rpc_task *task)
u32 *p = iov->iov_base, n;
int error = -EACCES;
if ((task->tk_rqstp->rq_rcv_buf.len & 3) != 0) {
/* RFC-1014 says that the representation of XDR data must be a
* multiple of four bytes
* - if it isn't pointer subtraction in the NFS client may give
* undefined results
*/
printk(KERN_WARNING
"call_verify: XDR representation not a multiple of"
" 4 bytes: 0x%x\n", task->tk_rqstp->rq_rcv_buf.len);
goto out_eio;
}
if ((len -= 3) < 0)
goto out_overflow;
p += 1; /* skip XID */
......
......@@ -539,6 +539,7 @@ rpc_depopulate(struct dentry *parent)
rpc_close_pipes(dentry->d_inode);
simple_unlink(dir, dentry);
}
inode_dir_notify(dir, DN_DELETE);
dput(dentry);
} while (n);
goto repeat;
......@@ -610,8 +611,8 @@ __rpc_rmdir(struct inode *dir, struct dentry *dentry)
int error;
shrink_dcache_parent(dentry);
if (dentry->d_inode)
rpc_close_pipes(dentry->d_inode);
if (d_unhashed(dentry))
return 0;
if ((error = simple_rmdir(dir, dentry)) != 0)
return error;
if (!error) {
......@@ -684,28 +685,20 @@ rpc_mkdir(char *path, struct rpc_clnt *rpc_client)
}
int
rpc_rmdir(char *path)
rpc_rmdir(struct dentry *dentry)
{
struct nameidata nd;
struct dentry *dentry;
struct dentry *parent;
struct inode *dir;
int error;
if ((error = rpc_lookup_parent(path, &nd)) != 0)
return error;
dir = nd.dentry->d_inode;
parent = dget_parent(dentry);
dir = parent->d_inode;
mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
dentry = lookup_one_len(nd.last.name, nd.dentry, nd.last.len);
if (IS_ERR(dentry)) {
error = PTR_ERR(dentry);
goto out_release;
}
rpc_depopulate(dentry);
error = __rpc_rmdir(dir, dentry);
dput(dentry);
out_release:
mutex_unlock(&dir->i_mutex);
rpc_release_path(&nd);
dput(parent);
return error;
}
......@@ -746,32 +739,26 @@ rpc_mkpipe(char *path, void *private, struct rpc_pipe_ops *ops, int flags)
}
int
rpc_unlink(char *path)
rpc_unlink(struct dentry *dentry)
{
struct nameidata nd;
struct dentry *dentry;
struct dentry *parent;
struct inode *dir;
int error;
int error = 0;
if ((error = rpc_lookup_parent(path, &nd)) != 0)
return error;
dir = nd.dentry->d_inode;
parent = dget_parent(dentry);
dir = parent->d_inode;
mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
dentry = lookup_one_len(nd.last.name, nd.dentry, nd.last.len);
if (IS_ERR(dentry)) {
error = PTR_ERR(dentry);
goto out_release;
}
if (!d_unhashed(dentry)) {
d_drop(dentry);
if (dentry->d_inode) {
rpc_close_pipes(dentry->d_inode);
error = simple_unlink(dir, dentry);
}
dput(dentry);
inode_dir_notify(dir, DN_DELETE);
out_release:
}
dput(dentry);
mutex_unlock(&dir->i_mutex);
rpc_release_path(&nd);
dput(parent);
return error;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment