forked from luck/tmp_suning_uos_patched
NFS: Prevent memory allocation failure in nfsacl_encode()
nfsacl_encode() allocates memory in certain cases. This of course
is not guaranteed to work.
Since commit 9f06c719
"SUNRPC: New xdr_streams XDR encoder API", the
kernel's XDR encoders can't return a result indicating possibly a
failure, so a memory allocation failure in nfsacl_encode() has become
fatal (ie, the XDR code Oopses) in some cases.
However, the allocated memory is a tiny fixed amount, on the order
of 40-50 bytes. We can easily use a stack-allocated buffer for
this, with only a wee bit of nose-holding.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
This commit is contained in:
parent
731f3f482a
commit
f61f6da0d5
|
@ -311,8 +311,8 @@ static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl,
|
||||||
if (!nfs_server_capable(inode, NFS_CAP_ACLS))
|
if (!nfs_server_capable(inode, NFS_CAP_ACLS))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
/* We are doing this here, because XDR marshalling can only
|
/* We are doing this here because XDR marshalling does not
|
||||||
return -ENOMEM. */
|
* return any results, it BUGs. */
|
||||||
status = -ENOSPC;
|
status = -ENOSPC;
|
||||||
if (acl != NULL && acl->a_count > NFS_ACL_MAX_ENTRIES)
|
if (acl != NULL && acl->a_count > NFS_ACL_MAX_ENTRIES)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
|
@ -42,6 +42,11 @@ struct nfsacl_encode_desc {
|
||||||
gid_t gid;
|
gid_t gid;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct nfsacl_simple_acl {
|
||||||
|
struct posix_acl acl;
|
||||||
|
struct posix_acl_entry ace[4];
|
||||||
|
};
|
||||||
|
|
||||||
static int
|
static int
|
||||||
xdr_nfsace_encode(struct xdr_array2_desc *desc, void *elem)
|
xdr_nfsace_encode(struct xdr_array2_desc *desc, void *elem)
|
||||||
{
|
{
|
||||||
|
@ -99,17 +104,22 @@ int nfsacl_encode(struct xdr_buf *buf, unsigned int base, struct inode *inode,
|
||||||
.uid = inode->i_uid,
|
.uid = inode->i_uid,
|
||||||
.gid = inode->i_gid,
|
.gid = inode->i_gid,
|
||||||
};
|
};
|
||||||
|
struct nfsacl_simple_acl aclbuf;
|
||||||
int err;
|
int err;
|
||||||
struct posix_acl *acl2 = NULL;
|
|
||||||
|
|
||||||
if (entries > NFS_ACL_MAX_ENTRIES ||
|
if (entries > NFS_ACL_MAX_ENTRIES ||
|
||||||
xdr_encode_word(buf, base, entries))
|
xdr_encode_word(buf, base, entries))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (encode_entries && acl && acl->a_count == 3) {
|
if (encode_entries && acl && acl->a_count == 3) {
|
||||||
/* Fake up an ACL_MASK entry. */
|
struct posix_acl *acl2 = &aclbuf.acl;
|
||||||
acl2 = posix_acl_alloc(4, GFP_KERNEL);
|
|
||||||
if (!acl2)
|
/* Avoid the use of posix_acl_alloc(). nfsacl_encode() is
|
||||||
return -ENOMEM;
|
* invoked in contexts where a memory allocation failure is
|
||||||
|
* fatal. Fortunately this fake ACL is small enough to
|
||||||
|
* construct on the stack. */
|
||||||
|
memset(acl2, 0, sizeof(acl2));
|
||||||
|
posix_acl_init(acl2, 4);
|
||||||
|
|
||||||
/* Insert entries in canonical order: other orders seem
|
/* Insert entries in canonical order: other orders seem
|
||||||
to confuse Solaris VxFS. */
|
to confuse Solaris VxFS. */
|
||||||
acl2->a_entries[0] = acl->a_entries[0]; /* ACL_USER_OBJ */
|
acl2->a_entries[0] = acl->a_entries[0]; /* ACL_USER_OBJ */
|
||||||
|
@ -120,8 +130,6 @@ int nfsacl_encode(struct xdr_buf *buf, unsigned int base, struct inode *inode,
|
||||||
nfsacl_desc.acl = acl2;
|
nfsacl_desc.acl = acl2;
|
||||||
}
|
}
|
||||||
err = xdr_encode_array2(buf, base + 4, &nfsacl_desc.desc);
|
err = xdr_encode_array2(buf, base + 4, &nfsacl_desc.desc);
|
||||||
if (acl2)
|
|
||||||
posix_acl_release(acl2);
|
|
||||||
if (!err)
|
if (!err)
|
||||||
err = 8 + nfsacl_desc.desc.elem_size *
|
err = 8 + nfsacl_desc.desc.elem_size *
|
||||||
nfsacl_desc.desc.array_len;
|
nfsacl_desc.desc.array_len;
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
|
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
|
|
||||||
|
EXPORT_SYMBOL(posix_acl_init);
|
||||||
EXPORT_SYMBOL(posix_acl_alloc);
|
EXPORT_SYMBOL(posix_acl_alloc);
|
||||||
EXPORT_SYMBOL(posix_acl_clone);
|
EXPORT_SYMBOL(posix_acl_clone);
|
||||||
EXPORT_SYMBOL(posix_acl_valid);
|
EXPORT_SYMBOL(posix_acl_valid);
|
||||||
|
@ -31,6 +32,16 @@ EXPORT_SYMBOL(posix_acl_create_masq);
|
||||||
EXPORT_SYMBOL(posix_acl_chmod_masq);
|
EXPORT_SYMBOL(posix_acl_chmod_masq);
|
||||||
EXPORT_SYMBOL(posix_acl_permission);
|
EXPORT_SYMBOL(posix_acl_permission);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Init a fresh posix_acl
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
posix_acl_init(struct posix_acl *acl, int count)
|
||||||
|
{
|
||||||
|
atomic_set(&acl->a_refcount, 1);
|
||||||
|
acl->a_count = count;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allocate a new ACL with the specified number of entries.
|
* Allocate a new ACL with the specified number of entries.
|
||||||
*/
|
*/
|
||||||
|
@ -40,10 +51,8 @@ posix_acl_alloc(int count, gfp_t flags)
|
||||||
const size_t size = sizeof(struct posix_acl) +
|
const size_t size = sizeof(struct posix_acl) +
|
||||||
count * sizeof(struct posix_acl_entry);
|
count * sizeof(struct posix_acl_entry);
|
||||||
struct posix_acl *acl = kmalloc(size, flags);
|
struct posix_acl *acl = kmalloc(size, flags);
|
||||||
if (acl) {
|
if (acl)
|
||||||
atomic_set(&acl->a_refcount, 1);
|
posix_acl_init(acl, count);
|
||||||
acl->a_count = count;
|
|
||||||
}
|
|
||||||
return acl;
|
return acl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -71,6 +71,7 @@ posix_acl_release(struct posix_acl *acl)
|
||||||
|
|
||||||
/* posix_acl.c */
|
/* posix_acl.c */
|
||||||
|
|
||||||
|
extern void posix_acl_init(struct posix_acl *, int);
|
||||||
extern struct posix_acl *posix_acl_alloc(int, gfp_t);
|
extern struct posix_acl *posix_acl_alloc(int, gfp_t);
|
||||||
extern struct posix_acl *posix_acl_clone(const struct posix_acl *, gfp_t);
|
extern struct posix_acl *posix_acl_clone(const struct posix_acl *, gfp_t);
|
||||||
extern int posix_acl_valid(const struct posix_acl *);
|
extern int posix_acl_valid(const struct posix_acl *);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user