diff options
author | Chuck Lever <chuck.lever@oracle.com> | 2011-01-20 22:05:38 -0500 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2011-01-25 15:24:47 -0500 |
commit | f61f6da0d53842e849bab7f69e1431bd3de1136d (patch) | |
tree | 8433904f645695338b98d3dc831631ffd6f129e5 /fs/nfs_common | |
parent | 731f3f482ad3b2c58a1af2d0a9a634a82803706a (diff) |
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>
Diffstat (limited to 'fs/nfs_common')
-rw-r--r-- | fs/nfs_common/nfsacl.c | 22 |
1 files changed, 15 insertions, 7 deletions
diff --git a/fs/nfs_common/nfsacl.c b/fs/nfs_common/nfsacl.c index a3e78bd18679..84c27d69d421 100644 --- a/fs/nfs_common/nfsacl.c +++ b/fs/nfs_common/nfsacl.c | |||
@@ -42,6 +42,11 @@ struct nfsacl_encode_desc { | |||
42 | gid_t gid; | 42 | gid_t gid; |
43 | }; | 43 | }; |
44 | 44 | ||
45 | struct nfsacl_simple_acl { | ||
46 | struct posix_acl acl; | ||
47 | struct posix_acl_entry ace[4]; | ||
48 | }; | ||
49 | |||
45 | static int | 50 | static int |
46 | xdr_nfsace_encode(struct xdr_array2_desc *desc, void *elem) | 51 | xdr_nfsace_encode(struct xdr_array2_desc *desc, void *elem) |
47 | { | 52 | { |
@@ -99,17 +104,22 @@ int nfsacl_encode(struct xdr_buf *buf, unsigned int base, struct inode *inode, | |||
99 | .uid = inode->i_uid, | 104 | .uid = inode->i_uid, |
100 | .gid = inode->i_gid, | 105 | .gid = inode->i_gid, |
101 | }; | 106 | }; |
107 | struct nfsacl_simple_acl aclbuf; | ||
102 | int err; | 108 | int err; |
103 | struct posix_acl *acl2 = NULL; | ||
104 | 109 | ||
105 | if (entries > NFS_ACL_MAX_ENTRIES || | 110 | if (entries > NFS_ACL_MAX_ENTRIES || |
106 | xdr_encode_word(buf, base, entries)) | 111 | xdr_encode_word(buf, base, entries)) |
107 | return -EINVAL; | 112 | return -EINVAL; |
108 | if (encode_entries && acl && acl->a_count == 3) { | 113 | if (encode_entries && acl && acl->a_count == 3) { |
109 | /* Fake up an ACL_MASK entry. */ | 114 | struct posix_acl *acl2 = &aclbuf.acl; |
110 | acl2 = posix_acl_alloc(4, GFP_KERNEL); | 115 | |
111 | if (!acl2) | 116 | /* Avoid the use of posix_acl_alloc(). nfsacl_encode() is |
112 | return -ENOMEM; | 117 | * invoked in contexts where a memory allocation failure is |
118 | * fatal. Fortunately this fake ACL is small enough to | ||
119 | * construct on the stack. */ | ||
120 | memset(acl2, 0, sizeof(acl2)); | ||
121 | posix_acl_init(acl2, 4); | ||
122 | |||
113 | /* Insert entries in canonical order: other orders seem | 123 | /* Insert entries in canonical order: other orders seem |
114 | to confuse Solaris VxFS. */ | 124 | to confuse Solaris VxFS. */ |
115 | acl2->a_entries[0] = acl->a_entries[0]; /* ACL_USER_OBJ */ | 125 | 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, | |||
120 | nfsacl_desc.acl = acl2; | 130 | nfsacl_desc.acl = acl2; |
121 | } | 131 | } |
122 | err = xdr_encode_array2(buf, base + 4, &nfsacl_desc.desc); | 132 | err = xdr_encode_array2(buf, base + 4, &nfsacl_desc.desc); |
123 | if (acl2) | ||
124 | posix_acl_release(acl2); | ||
125 | if (!err) | 133 | if (!err) |
126 | err = 8 + nfsacl_desc.desc.elem_size * | 134 | err = 8 + nfsacl_desc.desc.elem_size * |
127 | nfsacl_desc.desc.array_len; | 135 | nfsacl_desc.desc.array_len; |