diff options
author | Armin Kuster <akuster@mvista.com> | 2016-09-17 20:58:40 -0700 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2016-09-23 15:27:05 +0100 |
commit | 414aad04b631baddfc8e3dd02c305da0ddf9b883 (patch) | |
tree | 4e91d6a6b5dfaa82bc9eb3dc7cfb4e014c5a9ffb | |
parent | 8a7607f470ae2a63e9c7b0caddd0db2f6b259053 (diff) | |
download | poky-414aad04b631baddfc8e3dd02c305da0ddf9b883.tar.gz |
openssh: Security fix CVE-2016-6210
affects openssh < 7.3
(From OE-Core rev: 3bc2ea285637894d158d951ed721c54c1f1af4c3)
Signed-off-by: Armin Kuster <akuster@mvista.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
4 files changed, 289 insertions, 0 deletions
diff --git a/meta/recipes-connectivity/openssh/openssh/CVE-2016-6210.patch b/meta/recipes-connectivity/openssh/openssh/CVE-2016-6210.patch new file mode 100644 index 0000000000..e3072b43f5 --- /dev/null +++ b/meta/recipes-connectivity/openssh/openssh/CVE-2016-6210.patch | |||
@@ -0,0 +1,114 @@ | |||
1 | From 9286875a73b2de7736b5e50692739d314cd8d9dc Mon Sep 17 00:00:00 2001 | ||
2 | From: Darren Tucker <dtucker@zip.com.au> | ||
3 | Date: Fri, 15 Jul 2016 13:32:45 +1000 | ||
4 | Subject: [PATCH] Determine appropriate salt for invalid users. | ||
5 | |||
6 | When sshd is processing a non-PAM login for a non-existent user it uses | ||
7 | the string from the fakepw structure as the salt for crypt(3)ing the | ||
8 | password supplied by the client. That string has a Blowfish prefix, so on | ||
9 | systems that don't understand that crypt will fail fast due to an invalid | ||
10 | salt, and even on those that do it may have significantly different timing | ||
11 | from the hash methods used for real accounts (eg sha512). This allows | ||
12 | user enumeration by, eg, sending large password strings. This was noted | ||
13 | by EddieEzra.Harari at verint.com (CVE-2016-6210). | ||
14 | |||
15 | To mitigate, use the same hash algorithm that root uses for hashing | ||
16 | passwords for users that do not exist on the system. ok djm@ | ||
17 | |||
18 | Upstream-Status: Backport | ||
19 | OpenSSH < 7.3 | ||
20 | CVE: CVE-2016-6210 patch1 | ||
21 | Signed-off-by: Armin Kuster <akuster@mvista.com> | ||
22 | |||
23 | --- | ||
24 | auth-passwd.c | 12 ++++++++---- | ||
25 | openbsd-compat/xcrypt.c | 34 ++++++++++++++++++++++++++++++++++ | ||
26 | 2 files changed, 42 insertions(+), 4 deletions(-) | ||
27 | |||
28 | Index: openssh-7.1p2/auth-passwd.c | ||
29 | =================================================================== | ||
30 | --- openssh-7.1p2.orig/auth-passwd.c | ||
31 | +++ openssh-7.1p2/auth-passwd.c | ||
32 | @@ -198,7 +198,7 @@ int | ||
33 | sys_auth_passwd(Authctxt *authctxt, const char *password) | ||
34 | { | ||
35 | struct passwd *pw = authctxt->pw; | ||
36 | - char *encrypted_password; | ||
37 | + char *encrypted_password, *salt = NULL; | ||
38 | |||
39 | /* Just use the supplied fake password if authctxt is invalid */ | ||
40 | char *pw_password = authctxt->valid ? shadow_pw(pw) : pw->pw_passwd; | ||
41 | @@ -207,9 +207,13 @@ sys_auth_passwd(Authctxt *authctxt, cons | ||
42 | if (strcmp(pw_password, "") == 0 && strcmp(password, "") == 0) | ||
43 | return (1); | ||
44 | |||
45 | - /* Encrypt the candidate password using the proper salt. */ | ||
46 | - encrypted_password = xcrypt(password, | ||
47 | - (pw_password[0] && pw_password[1]) ? pw_password : "xx"); | ||
48 | + /* | ||
49 | + * Encrypt the candidate password using the proper salt, or pass a | ||
50 | + * NULL and let xcrypt pick one. | ||
51 | + */ | ||
52 | + if (authctxt->valid && pw_password[0] && pw_password[1]) | ||
53 | + salt = pw_password; | ||
54 | + encrypted_password = xcrypt(password, salt); | ||
55 | |||
56 | /* | ||
57 | * Authentication is accepted if the encrypted passwords | ||
58 | Index: openssh-7.1p2/openbsd-compat/xcrypt.c | ||
59 | =================================================================== | ||
60 | --- openssh-7.1p2.orig/openbsd-compat/xcrypt.c | ||
61 | +++ openssh-7.1p2/openbsd-compat/xcrypt.c | ||
62 | @@ -25,6 +25,7 @@ | ||
63 | #include "includes.h" | ||
64 | |||
65 | #include <sys/types.h> | ||
66 | +#include <string.h> | ||
67 | #include <unistd.h> | ||
68 | #include <pwd.h> | ||
69 | |||
70 | @@ -62,11 +63,44 @@ | ||
71 | # define crypt DES_crypt | ||
72 | # endif | ||
73 | |||
74 | +/* | ||
75 | + * Pick an appropriate password encryption type and salt for the running | ||
76 | + * system. | ||
77 | + */ | ||
78 | +static const char * | ||
79 | +pick_salt(void) | ||
80 | +{ | ||
81 | + struct passwd *pw; | ||
82 | + char *passwd, *p; | ||
83 | + size_t typelen; | ||
84 | + static char salt[32]; | ||
85 | + | ||
86 | + if (salt[0] != '\0') | ||
87 | + return salt; | ||
88 | + strlcpy(salt, "xx", sizeof(salt)); | ||
89 | + if ((pw = getpwuid(0)) == NULL) | ||
90 | + return salt; | ||
91 | + passwd = shadow_pw(pw); | ||
92 | + if (passwd[0] != '$' || (p = strrchr(passwd + 1, '$')) == NULL) | ||
93 | + return salt; /* no $, DES */ | ||
94 | + typelen = p - passwd + 1; | ||
95 | + strlcpy(salt, passwd, MIN(typelen, sizeof(salt))); | ||
96 | + explicit_bzero(passwd, strlen(passwd)); | ||
97 | + return salt; | ||
98 | +} | ||
99 | + | ||
100 | char * | ||
101 | xcrypt(const char *password, const char *salt) | ||
102 | { | ||
103 | char *crypted; | ||
104 | |||
105 | + /* | ||
106 | + * If we don't have a salt we are encrypting a fake password for | ||
107 | + * for timing purposes. Pick an appropriate salt. | ||
108 | + */ | ||
109 | + if (salt == NULL) | ||
110 | + salt = pick_salt(); | ||
111 | + | ||
112 | # ifdef HAVE_MD5_PASSWORDS | ||
113 | if (is_md5_salt(salt)) | ||
114 | crypted = md5_crypt(password, salt); | ||
diff --git a/meta/recipes-connectivity/openssh/openssh/CVE-2016-6210_p2.patch b/meta/recipes-connectivity/openssh/openssh/CVE-2016-6210_p2.patch new file mode 100644 index 0000000000..f27c74c7c1 --- /dev/null +++ b/meta/recipes-connectivity/openssh/openssh/CVE-2016-6210_p2.patch | |||
@@ -0,0 +1,110 @@ | |||
1 | From 283b97ff33ea2c641161950849931bd578de6946 Mon Sep 17 00:00:00 2001 | ||
2 | From: Darren Tucker <dtucker@zip.com.au> | ||
3 | Date: Fri, 15 Jul 2016 13:49:44 +1000 | ||
4 | Subject: [PATCH] Mitigate timing of disallowed users PAM logins. | ||
5 | |||
6 | When sshd decides to not allow a login (eg PermitRootLogin=no) and | ||
7 | it's using PAM, it sends a fake password to PAM so that the timing for | ||
8 | the failure is not noticeably different whether or not the password | ||
9 | is correct. This behaviour can be detected by sending a very long | ||
10 | password string which is slower to hash than the fake password. | ||
11 | |||
12 | Mitigate by constructing an invalid password that is the same length | ||
13 | as the one from the client and thus takes the same time to hash. | ||
14 | Diff from djm@ | ||
15 | |||
16 | Upstream-Status: Backport | ||
17 | CVE: CVE-2016-6210 patch2 | ||
18 | Signed-off-by: Armin Kuster <akuster@mvista.com> | ||
19 | |||
20 | --- | ||
21 | auth-pam.c | 35 +++++++++++++++++++++++++++++++---- | ||
22 | 1 file changed, 31 insertions(+), 4 deletions(-) | ||
23 | |||
24 | Index: openssh-7.1p2/auth-pam.c | ||
25 | =================================================================== | ||
26 | --- openssh-7.1p2.orig/auth-pam.c | ||
27 | +++ openssh-7.1p2/auth-pam.c | ||
28 | @@ -231,7 +231,6 @@ static int sshpam_account_status = -1; | ||
29 | static char **sshpam_env = NULL; | ||
30 | static Authctxt *sshpam_authctxt = NULL; | ||
31 | static const char *sshpam_password = NULL; | ||
32 | -static char badpw[] = "\b\n\r\177INCORRECT"; | ||
33 | |||
34 | /* Some PAM implementations don't implement this */ | ||
35 | #ifndef HAVE_PAM_GETENVLIST | ||
36 | @@ -809,12 +808,35 @@ sshpam_query(void *ctx, char **name, cha | ||
37 | return (-1); | ||
38 | } | ||
39 | |||
40 | +/* | ||
41 | + * Returns a junk password of identical length to that the user supplied. | ||
42 | + * Used to mitigate timing attacks against crypt(3)/PAM stacks that | ||
43 | + * vary processing time in proportion to password length. | ||
44 | + */ | ||
45 | +static char * | ||
46 | +fake_password(const char *wire_password) | ||
47 | +{ | ||
48 | + const char junk[] = "\b\n\r\177INCORRECT"; | ||
49 | + char *ret = NULL; | ||
50 | + size_t i, l = wire_password != NULL ? strlen(wire_password) : 0; | ||
51 | + | ||
52 | + if (l >= INT_MAX) | ||
53 | + fatal("%s: password length too long: %zu", __func__, l); | ||
54 | + | ||
55 | + ret = malloc(l + 1); | ||
56 | + for (i = 0; i < l; i++) | ||
57 | + ret[i] = junk[i % (sizeof(junk) - 1)]; | ||
58 | + ret[i] = '\0'; | ||
59 | + return ret; | ||
60 | +} | ||
61 | + | ||
62 | /* XXX - see also comment in auth-chall.c:verify_response */ | ||
63 | static int | ||
64 | sshpam_respond(void *ctx, u_int num, char **resp) | ||
65 | { | ||
66 | Buffer buffer; | ||
67 | struct pam_ctxt *ctxt = ctx; | ||
68 | + char *fake; | ||
69 | |||
70 | debug2("PAM: %s entering, %u responses", __func__, num); | ||
71 | switch (ctxt->pam_done) { | ||
72 | @@ -835,8 +857,11 @@ sshpam_respond(void *ctx, u_int num, cha | ||
73 | (sshpam_authctxt->pw->pw_uid != 0 || | ||
74 | options.permit_root_login == PERMIT_YES)) | ||
75 | buffer_put_cstring(&buffer, *resp); | ||
76 | - else | ||
77 | - buffer_put_cstring(&buffer, badpw); | ||
78 | + else { | ||
79 | + fake = fake_password(*resp); | ||
80 | + buffer_put_cstring(&buffer, fake); | ||
81 | + free(fake); | ||
82 | + } | ||
83 | if (ssh_msg_send(ctxt->pam_psock, PAM_AUTHTOK, &buffer) == -1) { | ||
84 | buffer_free(&buffer); | ||
85 | return (-1); | ||
86 | @@ -1180,6 +1205,7 @@ sshpam_auth_passwd(Authctxt *authctxt, c | ||
87 | { | ||
88 | int flags = (options.permit_empty_passwd == 0 ? | ||
89 | PAM_DISALLOW_NULL_AUTHTOK : 0); | ||
90 | + char *fake = NULL; | ||
91 | |||
92 | if (!options.use_pam || sshpam_handle == NULL) | ||
93 | fatal("PAM: %s called when PAM disabled or failed to " | ||
94 | @@ -1195,7 +1221,7 @@ sshpam_auth_passwd(Authctxt *authctxt, c | ||
95 | */ | ||
96 | if (!authctxt->valid || (authctxt->pw->pw_uid == 0 && | ||
97 | options.permit_root_login != PERMIT_YES)) | ||
98 | - sshpam_password = badpw; | ||
99 | + sshpam_password = fake = fake_password(password); | ||
100 | |||
101 | sshpam_err = pam_set_item(sshpam_handle, PAM_CONV, | ||
102 | (const void *)&passwd_conv); | ||
103 | @@ -1205,6 +1231,7 @@ sshpam_auth_passwd(Authctxt *authctxt, c | ||
104 | |||
105 | sshpam_err = pam_authenticate(sshpam_handle, flags); | ||
106 | sshpam_password = NULL; | ||
107 | + free(fake); | ||
108 | if (sshpam_err == PAM_SUCCESS && authctxt->valid) { | ||
109 | debug("PAM: password authentication accepted for %.100s", | ||
110 | authctxt->user); | ||
diff --git a/meta/recipes-connectivity/openssh/openssh/CVE-2016-6210_p3.patch b/meta/recipes-connectivity/openssh/openssh/CVE-2016-6210_p3.patch new file mode 100644 index 0000000000..790ec808be --- /dev/null +++ b/meta/recipes-connectivity/openssh/openssh/CVE-2016-6210_p3.patch | |||
@@ -0,0 +1,62 @@ | |||
1 | From dbf788b4d9d9490a5fff08a7b09888272bb10fcc Mon Sep 17 00:00:00 2001 | ||
2 | From: Darren Tucker <dtucker@zip.com.au> | ||
3 | Date: Thu, 21 Jul 2016 14:17:31 +1000 | ||
4 | Subject: [PATCH] Search users for one with a valid salt. | ||
5 | |||
6 | If the root account is locked (eg password "!!" or "*LK*") keep looking | ||
7 | until we find a user with a valid salt to use for crypting passwords of | ||
8 | invalid users. ok djm@ | ||
9 | |||
10 | Upstream-Status: Backport | ||
11 | CVE: CVE-2016-6210 | ||
12 | Signed-off-by: Armin Kuster <akuster@mvista.com> | ||
13 | |||
14 | --- | ||
15 | openbsd-compat/xcrypt.c | 24 +++++++++++++++--------- | ||
16 | 1 file changed, 15 insertions(+), 9 deletions(-) | ||
17 | |||
18 | diff --git a/openbsd-compat/xcrypt.c b/openbsd-compat/xcrypt.c | ||
19 | index 8913bb8..cf6a9b9 100644 | ||
20 | --- a/openbsd-compat/xcrypt.c | ||
21 | +++ b/openbsd-compat/xcrypt.c | ||
22 | @@ -65,7 +65,9 @@ | ||
23 | |||
24 | /* | ||
25 | * Pick an appropriate password encryption type and salt for the running | ||
26 | - * system. | ||
27 | + * system by searching through accounts until we find one that has a valid | ||
28 | + * salt. Usually this will be root unless the root account is locked out. | ||
29 | + * If we don't find one we return a traditional DES-based salt. | ||
30 | */ | ||
31 | static const char * | ||
32 | pick_salt(void) | ||
33 | @@ -78,14 +80,18 @@ pick_salt(void) | ||
34 | if (salt[0] != '\0') | ||
35 | return salt; | ||
36 | strlcpy(salt, "xx", sizeof(salt)); | ||
37 | - if ((pw = getpwuid(0)) == NULL) | ||
38 | - return salt; | ||
39 | - passwd = shadow_pw(pw); | ||
40 | - if (passwd[0] != '$' || (p = strrchr(passwd + 1, '$')) == NULL) | ||
41 | - return salt; /* no $, DES */ | ||
42 | - typelen = p - passwd + 1; | ||
43 | - strlcpy(salt, passwd, MIN(typelen, sizeof(salt))); | ||
44 | - explicit_bzero(passwd, strlen(passwd)); | ||
45 | + setpwent(); | ||
46 | + while ((pw = getpwent()) != NULL) { | ||
47 | + passwd = shadow_pw(pw); | ||
48 | + if (passwd[0] == '$' && (p = strrchr(passwd+1, '$')) != NULL) { | ||
49 | + typelen = p - passwd + 1; | ||
50 | + strlcpy(salt, passwd, MIN(typelen, sizeof(salt))); | ||
51 | + explicit_bzero(passwd, strlen(passwd)); | ||
52 | + goto out; | ||
53 | + } | ||
54 | + } | ||
55 | + out: | ||
56 | + endpwent(); | ||
57 | return salt; | ||
58 | } | ||
59 | |||
60 | -- | ||
61 | 2.7.4 | ||
62 | |||
diff --git a/meta/recipes-connectivity/openssh/openssh_7.1p2.bb b/meta/recipes-connectivity/openssh/openssh_7.1p2.bb index 92bc006bb2..6de1284f84 100644 --- a/meta/recipes-connectivity/openssh/openssh_7.1p2.bb +++ b/meta/recipes-connectivity/openssh/openssh_7.1p2.bb | |||
@@ -25,6 +25,9 @@ SRC_URI = "http://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-${PV}.tar | |||
25 | file://CVE-2016-1907_2.patch \ | 25 | file://CVE-2016-1907_2.patch \ |
26 | file://CVE-2016-1907_3.patch \ | 26 | file://CVE-2016-1907_3.patch \ |
27 | file://CVE-2016-3115.patch \ | 27 | file://CVE-2016-3115.patch \ |
28 | file://CVE-2016-6210.patch \ | ||
29 | file://CVE-2016-6210_p2.patch \ | ||
30 | file://CVE-2016-6210_p3.patch \ | ||
28 | " | 31 | " |
29 | 32 | ||
30 | PAM_SRC_URI = "file://sshd" | 33 | PAM_SRC_URI = "file://sshd" |