Skip to content

Commit 92eb6c3

Browse files
ebiggersherbertx
authored andcommittedNov 6, 2020
crypto: af_alg - avoid undefined behavior accessing salg_name
Commit 3f69cc6 ("crypto: af_alg - Allow arbitrarily long algorithm names") made the kernel start accepting arbitrarily long algorithm names in sockaddr_alg. However, the actual length of the salg_name field stayed at the original 64 bytes. This is broken because the kernel can access indices >= 64 in salg_name, which is undefined behavior -- even though the memory that is accessed is still located within the sockaddr structure. It would only be defined behavior if the array were properly marked as arbitrary-length (either by making it a flexible array, which is the recommended way these days, or by making it an array of length 0 or 1). We can't simply change salg_name into a flexible array, since that would break source compatibility with userspace programs that embed sockaddr_alg into another struct, or (more commonly) declare a sockaddr_alg like 'struct sockaddr_alg sa = { .salg_name = "foo" };'. One solution would be to change salg_name into a flexible array only when '#ifdef __KERNEL__'. However, that would keep userspace without an easy way to actually use the longer algorithm names. Instead, add a new structure 'sockaddr_alg_new' that has the flexible array field, and expose it to both userspace and the kernel. Make the kernel use it correctly in alg_bind(). This addresses the syzbot report "UBSAN: array-index-out-of-bounds in alg_bind" (https://syzkaller.appspot.com/bug?extid=92ead4eb8e26a26d465e). Reported-by: [email protected] Fixes: 3f69cc6 ("crypto: af_alg - Allow arbitrarily long algorithm names") Cc: <[email protected]> # v4.12+ Signed-off-by: Eric Biggers <[email protected]> Signed-off-by: Herbert Xu <[email protected]>
1 parent 2d65393 commit 92eb6c3

File tree

2 files changed

+23
-3
lines changed

2 files changed

+23
-3
lines changed
 

‎crypto/af_alg.c

+7-3
Original file line numberDiff line numberDiff line change
@@ -147,23 +147,27 @@ static int alg_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
147147
const u32 allowed = CRYPTO_ALG_KERN_DRIVER_ONLY;
148148
struct sock *sk = sock->sk;
149149
struct alg_sock *ask = alg_sk(sk);
150-
struct sockaddr_alg *sa = (void *)uaddr;
150+
struct sockaddr_alg_new *sa = (void *)uaddr;
151151
const struct af_alg_type *type;
152152
void *private;
153153
int err;
154154

155155
if (sock->state == SS_CONNECTED)
156156
return -EINVAL;
157157

158-
if (addr_len < sizeof(*sa))
158+
BUILD_BUG_ON(offsetof(struct sockaddr_alg_new, salg_name) !=
159+
offsetof(struct sockaddr_alg, salg_name));
160+
BUILD_BUG_ON(offsetof(struct sockaddr_alg, salg_name) != sizeof(*sa));
161+
162+
if (addr_len < sizeof(*sa) + 1)
159163
return -EINVAL;
160164

161165
/* If caller uses non-allowed flag, return error. */
162166
if ((sa->salg_feat & ~allowed) || (sa->salg_mask & ~allowed))
163167
return -EINVAL;
164168

165169
sa->salg_type[sizeof(sa->salg_type) - 1] = 0;
166-
sa->salg_name[sizeof(sa->salg_name) + addr_len - sizeof(*sa) - 1] = 0;
170+
sa->salg_name[addr_len - sizeof(*sa) - 1] = 0;
167171

168172
type = alg_get_type(sa->salg_type);
169173
if (PTR_ERR(type) == -ENOENT) {

‎include/uapi/linux/if_alg.h

+16
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,22 @@ struct sockaddr_alg {
2424
__u8 salg_name[64];
2525
};
2626

27+
/*
28+
* Linux v4.12 and later removed the 64-byte limit on salg_name[]; it's now an
29+
* arbitrary-length field. We had to keep the original struct above for source
30+
* compatibility with existing userspace programs, though. Use the new struct
31+
* below if support for very long algorithm names is needed. To do this,
32+
* allocate 'sizeof(struct sockaddr_alg_new) + strlen(algname) + 1' bytes, and
33+
* copy algname (including the null terminator) into salg_name.
34+
*/
35+
struct sockaddr_alg_new {
36+
__u16 salg_family;
37+
__u8 salg_type[14];
38+
__u32 salg_feat;
39+
__u32 salg_mask;
40+
__u8 salg_name[];
41+
};
42+
2743
struct af_alg_iv {
2844
__u32 ivlen;
2945
__u8 iv[0];

0 commit comments

Comments
 (0)
Please sign in to comment.