[patch] remove deadcode
Erik Hovland
erik at hovland.org
Fri Jul 7 05:49:40 WST 2006
On Wed, Jul 05, 2006 at 03:33:14PM -0700, Erik Hovland wrote:
> This patch removes an #if 0 set of code. And it removes a passphrase
> check which cannot happen.
I have finished an audit of dropbear and decided to reply to my own post
because my current draft of patches expands on the same file (and a few
others.
The patches should be consistent with current mtn repo and should have
annotations in each file. I am willing to rework any patch that doesn't
meet the statisfaction of the devs. So please send feedback.
BTW, almost all of these 'bugs' cause no harm that I can tell. So don't
think there is any serious problems here. It is really just dotting i's
and crossing t's.
E
--
Erik Hovland
mail: erik AT hovland DOT org
web: http://hovland.org/
PGP/GPG public key available on request
-------------- next part --------------
BUG: mp_div_2d returns status and it isn't checked.
FIX: Check and return status.
--- libtommath/bn_mp_div.c old
+++ libtommath/bn_mp_div.c new
@@ -269,7 +269,8 @@ int mp_div (mp_int * a, mp_int * b, mp_i
}
if (d != NULL) {
- mp_div_2d (&x, norm, &x, NULL);
+ if ((res = mp_div_2d (&x, norm, &x, NULL)) != MP_OKAY)
+ return res;
mp_exch (&x, d);
}
#
# old_revision [4c32ad8064e93b83c6d635d193b34d5f9112d1ae]
#
# patch "libtommath/bn_mp_div.c"
# from [0f214a2ee7c1cfd6152ebd473d2f04db67f2f86c]
# to [de1182b10274bd4e691094aef260abe21fb8f5cc]
#
-------------- next part --------------
BUG: The strings 'name' and 'instruction' are always allocated
but are only freed if the length of the string is greater then
zero. They should always be freed.
FIX: take the m_free(<string>) out of the conditional
--- cli-authinteract.c old
+++ cli-authinteract.c new
@@ -99,13 +99,13 @@ void recv_msg_userauth_info_request() {
if (strlen(name) > 0) {
cleantext(name);
fprintf(stderr, "%s", name);
- m_free(name);
}
+ m_free(name);
if (strlen(instruction) > 0) {
cleantext(instruction);
fprintf(stderr, "%s", instruction);
- m_free(instruction);
}
+ m_free(instruction);
for (i = 0; i < num_prompts; i++) {
unsigned int response_len = 0;
#
# old_revision [4c32ad8064e93b83c6d635d193b34d5f9112d1ae]
#
# patch "cli-authinteract.c"
# from [c65d9c192f42ce4654ec4e8d6765b11e4f5ca9a9]
# to [301ca11246ed5945026d0d1bc4c407ddc5a50519]
#
-------------- next part --------------
BUG: keybuf can memory leak.
FIX: Add an m_free(keybuf) once we are done matching the keys.
--- cli-authpubkey.c old
+++ cli-authpubkey.c new
@@ -112,6 +112,7 @@ void recv_msg_userauth_pk_ok() {
/* Success */
break;
}
+ m_free(keybuf);
if (keyitem != NULL) {
TRACE(("matching key"))
#
# old_revision [4c32ad8064e93b83c6d635d193b34d5f9112d1ae]
#
# patch "cli-authpubkey.c"
# from [f4b6c66351e60851c73405d8ecf4676557f0da30]
# to [05a5cc2282123b73b132a498c46279ac93d273a3]
#
-------------- next part --------------
BUG: The fingerprint can leak if response is not 'y'.
FIX: Free the fingerprint buffer after we are done printing it.
--- cli-kex.c old
+++ cli-kex.c new
@@ -122,6 +122,7 @@ static void ask_to_confirm(unsigned char
fprintf(stderr, "\nHost '%s' is not in the trusted hosts file.\n(fingerprint %s)\nDo you want to continue connecting? (y/n)\n",
cli_opts.remotehost,
fp);
+ m_free(fp);
tty = fopen(_PATH_TTY, "r");
if (tty) {
@@ -132,7 +133,6 @@ static void ask_to_confirm(unsigned char
}
if (response == 'y') {
- m_free(fp);
return;
}
#
# old_revision [4c32ad8064e93b83c6d635d193b34d5f9112d1ae]
#
# patch "cli-kex.c"
# from [3e15b2b2d3b42e45f38782414b709a48f11c56d9]
# to [28231814a32f302b4dc82265fecf9d4850e5a001]
#
-------------- next part --------------
Remove a stale bit of code since it should be
obvious waht is happening.
--- cli-service.c old
+++ cli-service.c new
@@ -82,6 +82,4 @@ void recv_msg_service_accept() {
}
dropbear_exit("unrecognised service accept");
- /* m_free(servicename); not reached */
-
}
#
# old_revision [4c32ad8064e93b83c6d635d193b34d5f9112d1ae]
#
# patch "cli-service.c"
# from [4b9ba5f1287845d47ba61d813ba53d143de4b804]
# to [c9175c55722051be489796ffa96f171ac70f73c4]
#
-------------- next part --------------
BUG: The call find_cipher can return a negative value if things don't
go right. We don't know that find_cipher is the cause of cbc_start() unless
we check find_cipher before calling cbc_start(). BTW, cbc_start() does check that
the cipher it is handed is OK. So there is no seriouse damage.
FIX: Do the find_cipher() and check it.
NOTE: I consider this fix to be purely pedantic.
--- common-kex.c old
+++ common-kex.c new
@@ -262,6 +262,7 @@ void gen_new_keys() {
hash_state hs;
unsigned int C2S_keysize, S2C_keysize;
char mactransletter, macrecvletter; /* Client or server specific */
+ int recv_cipher = 0, trans_cipher = 0;
TRACE(("enter gen_new_keys"))
/* the dh_K and hash are the start of all hashes, we make use of that */
@@ -298,17 +299,21 @@ void gen_new_keys() {
hashkeys(C2S_key, C2S_keysize, &hs, 'C');
hashkeys(S2C_key, S2C_keysize, &hs, 'D');
+ if ((recv_cipher = find_cipher(ses.newkeys->recv_algo_crypt->cipherdesc->name)) < 0)
+ dropbear_exit("crypto error");
+
if (cbc_start(
- find_cipher(ses.newkeys->recv_algo_crypt->cipherdesc->name),
- recv_IV, recv_key,
+ recv_cipher, recv_IV, recv_key,
ses.newkeys->recv_algo_crypt->keysize, 0,
&ses.newkeys->recv_symmetric_struct) != CRYPT_OK) {
dropbear_exit("crypto error");
}
+ if ((trans_cipher = find_cipher(ses.newkeys->trans_algo_crypt->cipherdesc->name)) < 0)
+ dropbear_exit("crypto error");
+
if (cbc_start(
- find_cipher(ses.newkeys->trans_algo_crypt->cipherdesc->name),
- trans_IV, trans_key,
+ trans_cipher, trans_IV, trans_key,
ses.newkeys->trans_algo_crypt->keysize, 0,
&ses.newkeys->trans_symmetric_struct) != CRYPT_OK) {
dropbear_exit("crypto error");
@@ -517,7 +522,8 @@ void kexdh_comb_key(mp_int *dh_pub_us, m
hash_state hs;
/* read the prime and generator*/
- mp_init(&dh_p);
+ if (mp_init(&dh_p) != MP_OKAY)
+ dropbear_exit("Diffie-Hellman error");
bytes_to_mp(&dh_p, dh_p_val, DH_P_LEN);
/* Check that dh_pub_them (dh_e or dh_f) is in the range [1, p-1] */
#
# old_revision [4c32ad8064e93b83c6d635d193b34d5f9112d1ae]
#
# patch "common-kex.c"
# from [b06f424fe466a6d3ecfb7072d59457ebb39c8780]
# to [a5be345f9dd6aa724d95134f13a4fe36bf83320e]
#
-------------- next part --------------
BUG: The call to sign_key_free(key) could be called before key is allocated
because of the goto usage.
FIX: Check key before making the call.
--- dropbearkey.c old
+++ dropbearkey.c new
@@ -283,8 +283,10 @@ out:
buf_burn(buf);
buf_free(buf);
buf = NULL;
- sign_key_free(key);
- key = NULL;
+ if (key) {
+ sign_key_free(key);
+ key = NULL;
+ }
exit(err);
}
#
# old_revision [4c32ad8064e93b83c6d635d193b34d5f9112d1ae]
#
# patch "dropbearkey.c"
# from [c2a49c53fa12e4bf57922462e55b243119bb4043]
# to [eb8195c08cabcd2516d8fb5a461b4fa29e933cf0]
#
-------------- next part --------------
BUG: We could leak the file descriptor in certain cases.
FIX: Add an fclose to the calls if we had to do an explicit fopen.
BUG: The switch to using a goto instead of the code in the conditional
block makes the following 'if (passphrase)' call redundant.
NOTE: The code in the #if 0 comments is removed as well.
--- keyimport.c old
+++ keyimport.c new
@@ -362,6 +362,7 @@ static struct openssh_key *load_openssh_
{
struct openssh_key *ret;
FILE *fp;
+ int close_fp = 0;
char buffer[256];
char *errmsg = NULL, *p = NULL;
int headers_done;
@@ -377,9 +378,12 @@ static struct openssh_key *load_openssh_
fp = stdin;
} else {
fp = fopen(filename, "r");
+ close_fp = 1;
}
if (!fp) {
errmsg = "Unable to open key file";
+ if (close_fp)
+ close_fp = 0;
goto error;
}
if (!fgets(buffer, sizeof(buffer), fp) ||
@@ -482,6 +486,8 @@ static struct openssh_key *load_openssh_
memset(&ret, 0, sizeof(ret));
m_free(ret);
}
+ if (close_fp)
+ fclose(fp);
if (errmsg) {
fprintf(stderr, "Error: %s\n", errmsg);
}
@@ -926,40 +932,6 @@ static int openssh_write(const char *fil
if (passphrase) {
fprintf(stderr, "Encrypted keys aren't supported currently\n");
goto error;
-#if 0
- /*
- * Invent an iv. Then derive encryption key from passphrase
- * and iv/salt:
- *
- * - let block A equal MD5(passphrase || iv)
- * - let block B equal MD5(A || passphrase || iv)
- * - block C would be MD5(B || passphrase || iv) and so on
- * - encryption key is the first N bytes of A || B
- */
- struct MD5Context md5c;
- unsigned char keybuf[32];
-
- for (i = 0; i < 8; i++) iv[i] = random_byte();
-
- MD5Init(&md5c);
- MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase));
- MD5Update(&md5c, iv, 8);
- MD5Final(keybuf, &md5c);
-
- MD5Init(&md5c);
- MD5Update(&md5c, keybuf, 16);
- MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase));
- MD5Update(&md5c, iv, 8);
- MD5Final(keybuf+16, &md5c);
-
- /*
- * Now encrypt the key blob.
- */
- des3_encrypt_pubkey_ossh(keybuf, iv, outblob, outlen);
-
- memset(&md5c, 0, sizeof(md5c));
- memset(keybuf, 0, sizeof(keybuf));
-#endif
}
/*
@@ -976,12 +948,6 @@ static int openssh_write(const char *fil
goto error;
}
fputs(header, fp);
- if (passphrase) {
- fprintf(fp, "Proc-Type: 4,ENCRYPTED\nDEK-Info: DES-EDE3-CBC,");
- for (i = 0; i < 8; i++)
- fprintf(fp, "%02X", iv[i]);
- fprintf(fp, "\n\n");
- }
base64_encode_fp(fp, outblob, outlen, 64);
fputs(footer, fp);
fclose(fp);
#
# old_revision [4c32ad8064e93b83c6d635d193b34d5f9112d1ae]
#
# patch "keyimport.c"
# from [4d6aa56819151b18d6828b1a9b1db0b9864e40b3]
# to [61087db466ee8df9c0fc12f65affa660f62ab9ea]
#
-------------- next part --------------
BUG: The libtommath call mp_invmod does return a value but it is not checked.
FIX: Add a check.
--- rsa.c old
+++ rsa.c new
@@ -286,7 +286,8 @@ void buf_put_rsa_sign(buffer* buf, rsa_k
/* em' = em * r^e mod n */
mp_exptmod(&rsa_tmp2, key->e, key->n, &rsa_s); /* rsa_s used as a temp var*/
- mp_invmod(&rsa_tmp2, key->n, &rsa_tmp3);
+ if (mp_invmod(&rsa_tmp2, key->n, &rsa_tmp3) != MP_OKAY)
+ dropbear_exit("rsa error");
mp_mulmod(&rsa_tmp1, &rsa_s, key->n, &rsa_tmp2);
/* rsa_tmp2 is em' */
#
# old_revision [4c32ad8064e93b83c6d635d193b34d5f9112d1ae]
#
# patch "rsa.c"
# from [792f3ff06fe126d3b69a067e56be005c57c8c968]
# to [9849a7e08b3d656e9deb9c9330499359a1e3b961]
#
-------------- next part --------------
BUG: Potentially dangeruous use of stat/chown/chmod. Since we use the
string tty_name for all calls on the tty device it is possible for
someone to be underhanded and use these calls and that string
to elevate priviledges.
FIX: Switch to using fstat/fchown/fchmod and obtain a file
descriptor instead of using a string.
NOTE: I doubt this can be exploited. But why leave it hanging around.
--- sshpty.c old
+++ sshpty.c new
@@ -356,6 +356,7 @@ void
pty_setowner(struct passwd *pw, const char *tty_name)
{
struct group *grp;
+ FILE* ttyfd;
gid_t gid;
mode_t mode;
struct stat st;
@@ -375,21 +376,25 @@ pty_setowner(struct passwd *pw, const ch
* Warn but continue if filesystem is read-only and the uids match/
* tty is owned by root.
*/
- if (stat(tty_name, &st)) {
- dropbear_exit("pty_setowner: stat(%.101s) failed: %.100s",
+ if (!(ttyfd = fopen(tty_name, "w+"))) {
+ dropbear_exit("pty_setowner: fopen(%.101s) failed: %.100s",
+ tty_name, strerror(errno));
+ }
+ if (fstat(ttyfd, &st)) {
+ dropbear_exit("pty_setowner: fstat(%.101s) failed: %.100s",
tty_name, strerror(errno));
}
if (st.st_uid != pw->pw_uid || st.st_gid != gid) {
- if (chown(tty_name, pw->pw_uid, gid) < 0) {
+ if (fchown(ttyfd, pw->pw_uid, gid) < 0) {
if (errno == EROFS &&
(st.st_uid == pw->pw_uid || st.st_uid == 0)) {
dropbear_log(LOG_ERR,
- "chown(%.100s, %u, %u) failed: %.100s",
+ "fchown(%.100s, %u, %u) failed: %.100s",
tty_name, (unsigned int)pw->pw_uid, (unsigned int)gid,
strerror(errno));
} else {
- dropbear_exit("chown(%.100s, %u, %u) failed: %.100s",
+ dropbear_exit("fchown(%.100s, %u, %u) failed: %.100s",
tty_name, (unsigned int)pw->pw_uid, (unsigned int)gid,
strerror(errno));
}
@@ -397,16 +402,18 @@ pty_setowner(struct passwd *pw, const ch
}
if ((st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO)) != mode) {
- if (chmod(tty_name, mode) < 0) {
+ if (fchmod(ttyfd, mode) < 0) {
if (errno == EROFS &&
(st.st_mode & (S_IRGRP | S_IROTH)) == 0) {
dropbear_log(LOG_ERR,
- "chmod(%.100s, 0%o) failed: %.100s",
+ "fchmod(%.100s, 0%o) failed: %.100s",
tty_name, mode, strerror(errno));
} else {
- dropbear_exit("chmod(%.100s, 0%o) failed: %.100s",
+ dropbear_exit("fchmod(%.100s, 0%o) failed: %.100s",
tty_name, mode, strerror(errno));
}
}
}
+ if (ttyfd)
+ fclose(ttyfd);
}
#
# old_revision [4c32ad8064e93b83c6d635d193b34d5f9112d1ae]
#
# patch "sshpty.c"
# from [5f45b06f6c68c3a4b163a7caf5efd681cd2dd7b8]
# to [ead81d13baa32bcdb4394eb04e920b289e52df06]
#
-------------- next part --------------
BUG: Since exit is set to NULL at the end of the loop, it is possible to
dereference exit as NULL (and segfault).
FIX: Co-opt the check for the race condition to make sure that exit
points at something valid.
--- svr-chansession.c old
+++ svr-chansession.c new
@@ -99,7 +99,7 @@ static void sesssigchild_handler(int UNU
/* If the pid wasn't matched, then we might have hit the race mentioned
* above. So we just store the info for the parent to deal with */
- if (i == svr_ses.childpidsize) {
+ if (i == svr_ses.childpidsize || !exit) {
exit = &svr_ses.lastexit;
}
#
# old_revision [4c32ad8064e93b83c6d635d193b34d5f9112d1ae]
#
# patch "svr-chansession.c"
# from [030d10c1bd3ddf7d5e1a85165ee24685214a6b48]
# to [609b0035bc1da3b426ac09adf1780a03aaf6c70e]
#
-------------- next part --------------
BUG: buf_getmpint() is not checked to see if it worked.
FIX: Add a check and exit if it doesn't.
--- svr-kex.c old
+++ svr-kex.c new
@@ -52,7 +52,8 @@ void recv_msg_kexdh_init() {
}
m_mp_init(&dh_e);
- buf_getmpint(ses.payload, &dh_e);
+ if (buf_getmpint(ses.payload, &dh_e) != DROPBEAR_SUCCESS)
+ dropbear_exit("Unable to retrieve mp_int from buffer");
send_msg_kexdh_reply(&dh_e);
#
# old_revision [4c32ad8064e93b83c6d635d193b34d5f9112d1ae]
#
# patch "svr-kex.c"
# from [307e41123e5a9962093a7285f73a2400916bf526]
# to [0e5589d22c3cc3c0fc1e84a13d4734c463ac3e9f]
#
-------------- next part --------------
BUG: If you use the pointer that is obtained from tcpinfo and tcpinfo is NULL
this call will segfault.
FIX: Use the pointer var bindaddr instead since it is the same thing.
--- svr-tcpfwd.c old
+++ svr-tcpfwd.c new
@@ -216,7 +216,7 @@ out:
if (ret == DROPBEAR_FAILURE) {
/* we only free it if a listener wasn't created, since the listener
* has to remember it if it's to be cancelled */
- m_free(tcpinfo->listenaddr);
+ m_free(bindaddr);
m_free(tcpinfo);
}
TRACE(("leave remotetcpreq"))
#
# old_revision [4c32ad8064e93b83c6d635d193b34d5f9112d1ae]
#
# patch "svr-tcpfwd.c"
# from [aa3d9bd98b61f4a84f5b28b1debc66a2b398045b]
# to [dba94b5f63e6e5cfcc4eb61809f890715c8eacf5]
#
-------------- next part --------------
BUG: Since listen_tcpfwd() does not free the buffer that tcpinfo
points to when it notices a check in a previous block of code, it
is inconsistent to free tcpinfo in this check. Especially since the
call is responsible for giving a valid pointer to listen_tcpfwd().
FIX: Remove the m_free(tcpinfo); call so that listen_tcpfwd()
always behaves the same when bailing out.
--- tcp-accept.c old
+++ tcp-accept.c new
@@ -131,7 +131,6 @@ int listen_tcpfwd(struct TCPListener* tc
tcp_acceptor, cleanup_tcp);
if (listener == NULL) {
- m_free(tcpinfo);
TRACE(("leave listen_tcpfwd: listener failed"))
return DROPBEAR_FAILURE;
}
#
# old_revision [4c32ad8064e93b83c6d635d193b34d5f9112d1ae]
#
# patch "tcp-accept.c"
# from [30c320bfdcfb7fd4dfbb35d8af5afdb1778f1d7d]
# to [69b03a9fd536daae6f43bc740522947591247de0]
#
More information about the Dropbear
mailing list