diff --git a/Makefile.in b/Makefile.in index e10f3742a..5870e9e6e 100644 --- a/Makefile.in +++ b/Makefile.in @@ -236,6 +236,8 @@ clean: regressclean rm -f regress/unittests/sshkey/test_sshkey rm -f regress/unittests/bitmap/*.o rm -f regress/unittests/bitmap/test_bitmap + rm -f regress/unittests/conversion/*.o + rm -f regress/unittests/conversion/test_conversion rm -f regress/unittests/hostkeys/*.o rm -f regress/unittests/hostkeys/test_hostkeys rm -f regress/unittests/kex/*.o @@ -262,6 +264,8 @@ distclean: regressclean rm -f regress/unittests/sshkey/test_sshkey rm -f regress/unittests/bitmap/*.o rm -f regress/unittests/bitmap/test_bitmap + rm -f regress/unittests/conversion/*.o + rm -f regress/unittests/conversion/test_conversion rm -f regress/unittests/hostkeys/*.o rm -f regress/unittests/hostkeys/test_hostkeys rm -f regress/unittests/kex/*.o @@ -426,6 +430,8 @@ regress-prep: mkdir -p `pwd`/regress/unittests/sshkey [ -d `pwd`/regress/unittests/bitmap ] || \ mkdir -p `pwd`/regress/unittests/bitmap + [ -d `pwd`/regress/unittests/conversion ] || \ + mkdir -p `pwd`/regress/unittests/conversion [ -d `pwd`/regress/unittests/hostkeys ] || \ mkdir -p `pwd`/regress/unittests/hostkeys [ -d `pwd`/regress/unittests/kex ] || \ @@ -503,6 +509,16 @@ regress/unittests/bitmap/test_bitmap$(EXEEXT): ${UNITTESTS_TEST_BITMAP_OBJS} \ regress/unittests/test_helper/libtest_helper.a \ -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS) +UNITTESTS_TEST_CONVERSION_OBJS=\ + regress/unittests/conversion/tests.o + +regress/unittests/conversion/test_conversion$(EXEEXT): \ + ${UNITTESTS_TEST_CONVERSION_OBJS} \ + regress/unittests/test_helper/libtest_helper.a libssh.a + $(LD) -o $@ $(LDFLAGS) $(UNITTESTS_TEST_CONVERSION_OBJS) \ + regress/unittests/test_helper/libtest_helper.a \ + -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS) + UNITTESTS_TEST_KEX_OBJS=\ regress/unittests/kex/tests.o \ regress/unittests/kex/test_kex.o @@ -558,13 +574,14 @@ regress-binaries: regress/modpipe$(EXEEXT) \ regress/unittests/sshbuf/test_sshbuf$(EXEEXT) \ regress/unittests/sshkey/test_sshkey$(EXEEXT) \ regress/unittests/bitmap/test_bitmap$(EXEEXT) \ + regress/unittests/conversion/test_conversion$(EXEEXT) \ regress/unittests/hostkeys/test_hostkeys$(EXEEXT) \ regress/unittests/kex/test_kex$(EXEEXT) \ regress/unittests/match/test_match$(EXEEXT) \ regress/unittests/utf8/test_utf8$(EXEEXT) \ regress/misc/kexfuzz/kexfuzz$(EXEEXT) -tests interop-tests t-exec: regress-prep regress-binaries $(TARGETS) +tests interop-tests t-exec unit: regress-prep regress-binaries $(TARGETS) BUILDDIR=`pwd`; \ TEST_SSH_SCP="$${BUILDDIR}/scp"; \ TEST_SSH_SSH="$${BUILDDIR}/ssh"; \ diff --git a/configure.ac b/configure.ac index 972addfeb..f5c1bea02 100644 --- a/configure.ac +++ b/configure.ac @@ -2531,8 +2531,8 @@ if test "x$openssl" = "xyes" ; then ssl_library_ver=`cat conftest.ssllibver` # Check version is supported. case "$ssl_library_ver" in - 0090[[0-7]]*|009080[[0-5]]*) - AC_MSG_ERROR([OpenSSL >= 0.9.8f required (have "$ssl_library_ver")]) + 10000*|0*) + AC_MSG_ERROR([OpenSSL >= 1.0.1 required (have "$ssl_library_ver")]) ;; *) ;; esac diff --git a/krl.c b/krl.c index e271a1934..3f28178b7 100644 --- a/krl.c +++ b/krl.c @@ -14,7 +14,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $OpenBSD: krl.c,v 1.38 2016/09/12 01:22:38 deraadt Exp $ */ +/* $OpenBSD: krl.c,v 1.39 2017/03/10 07:18:32 dtucker Exp $ */ #include "includes.h" @@ -1089,7 +1089,7 @@ ssh_krl_from_blob(struct sshbuf *buf, struct ssh_krl **krlp, break; case KRL_SECTION_SIGNATURE: /* Handled above, but still need to stay in synch */ - sshbuf_reset(sect); + sshbuf_free(sect); sect = NULL; if ((r = sshbuf_skip_string(copy)) != 0) goto out; @@ -1288,7 +1288,8 @@ ssh_krl_file_contains_key(const char *path, const struct sshkey *key) debug2("%s: checking KRL %s", __func__, path); r = ssh_krl_check_key(krl, key); out: - close(fd); + if (fd != -1) + close(fd); sshbuf_free(krlbuf); ssh_krl_free(krl); if (r != 0) diff --git a/misc.c b/misc.c index 8a644051f..70bf51735 100644 --- a/misc.c +++ b/misc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: misc.c,v 1.107 2016/11/30 00:28:31 dtucker Exp $ */ +/* $OpenBSD: misc.c,v 1.109 2017/03/14 00:55:37 dtucker Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2005,2006 Damien Miller. All rights reserved. @@ -310,7 +310,7 @@ a2tun(const char *s, int *remote) long convtime(const char *s) { - long total, secs; + long total, secs, multiplier = 1; const char *p; char *endp; @@ -337,23 +337,28 @@ convtime(const char *s) break; case 'm': case 'M': - secs *= MINUTES; + multiplier = MINUTES; break; case 'h': case 'H': - secs *= HOURS; + multiplier = HOURS; break; case 'd': case 'D': - secs *= DAYS; + multiplier = DAYS; break; case 'w': case 'W': - secs *= WEEKS; + multiplier = WEEKS; break; default: return -1; } + if (secs >= LONG_MAX / multiplier) + return -1; + secs *= multiplier; + if (total >= LONG_MAX - secs) + return -1; total += secs; if (total < 0) return -1; diff --git a/openbsd-compat/fmt_scaled.c b/openbsd-compat/fmt_scaled.c index edd682a49..e5533b2de 100644 --- a/openbsd-compat/fmt_scaled.c +++ b/openbsd-compat/fmt_scaled.c @@ -1,4 +1,4 @@ -/* $OpenBSD: fmt_scaled.c,v 1.9 2007/03/20 03:42:52 tedu Exp $ */ +/* $OpenBSD: fmt_scaled.c,v 1.13 2017/03/11 23:37:23 djm Exp $ */ /* * Copyright (c) 2001, 2002, 2003 Ian F. Darwin. All rights reserved. @@ -69,7 +69,7 @@ static long long scale_factors[] = { #define MAX_DIGITS (SCALE_LENGTH * 3) /* XXX strlen(sprintf("%lld", -1)? */ -/** Convert the given input string "scaled" into numeric in "result". +/* Convert the given input string "scaled" into numeric in "result". * Return 0 on success, -1 and errno set on error. */ int @@ -81,7 +81,7 @@ scan_scaled(char *scaled, long long *result) long long scale_fact = 1, whole = 0, fpart = 0; /* Skip leading whitespace */ - while (isascii(*p) && isspace(*p)) + while (isascii((unsigned char)*p) && isspace((unsigned char)*p)) ++p; /* Then at most one leading + or - */ @@ -108,7 +108,8 @@ scan_scaled(char *scaled, long long *result) * (but note that E for Exa might look like e to some!). * Advance 'p' to end, to get scale factor. */ - for (; isascii(*p) && (isdigit(*p) || *p=='.'); ++p) { + for (; isascii((unsigned char)*p) && + (isdigit((unsigned char)*p) || *p=='.'); ++p) { if (*p == '.') { if (fract_digits > 0) { /* oops, more than one '.' */ errno = EINVAL; @@ -124,6 +125,10 @@ scan_scaled(char *scaled, long long *result) /* ignore extra fractional digits */ continue; fract_digits++; /* for later scaling */ + if (fpart >= LLONG_MAX / 10) { + errno = ERANGE; + return -1; + } fpart *= 10; fpart += i; } else { /* normal digit */ @@ -131,6 +136,10 @@ scan_scaled(char *scaled, long long *result) errno = ERANGE; return -1; } + if (whole >= LLONG_MAX / 10) { + errno = ERANGE; + return -1; + } whole *= 10; whole += i; } @@ -150,17 +159,22 @@ scan_scaled(char *scaled, long long *result) /* Validate scale factor, and scale whole and fraction by it. */ for (i = 0; i < SCALE_LENGTH; i++) { - /** Are we there yet? */ + /* Are we there yet? */ if (*p == scale_chars[i] || - *p == tolower(scale_chars[i])) { + *p == tolower((unsigned char)scale_chars[i])) { /* If it ends with alphanumerics after the scale char, bad. */ - if (isalnum(*(p+1))) { + if (isalnum((unsigned char)*(p+1))) { errno = EINVAL; return -1; } scale_fact = scale_factors[i]; + if (whole >= LLONG_MAX / scale_fact) { + errno = ERANGE; + return -1; + } + /* scale whole part */ whole *= scale_fact; @@ -181,7 +195,9 @@ scan_scaled(char *scaled, long long *result) return 0; } } - errno = ERANGE; + + /* Invalid unit or character */ + errno = EINVAL; return -1; } @@ -196,7 +212,7 @@ fmt_scaled(long long number, char *result) unsigned int i; unit_type unit = NONE; - abval = (number < 0LL) ? -number : number; /* no long long_abs yet */ + abval = llabs(number); /* Not every negative long long has a positive representation. * Also check for numbers that are just too darned big to format diff --git a/packet.c b/packet.c index 01e2d45bd..2f3a2ec70 100644 --- a/packet.c +++ b/packet.c @@ -1,4 +1,4 @@ -/* $OpenBSD: packet.c,v 1.246 2017/02/28 06:10:08 djm Exp $ */ +/* $OpenBSD: packet.c,v 1.247 2017/03/11 13:07:35 markus Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -1850,11 +1850,11 @@ ssh_packet_read_poll2(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p) if (r != SSH_ERR_MAC_INVALID) goto out; logit("Corrupted MAC on input."); - if (need > PACKET_MAX_SIZE) + if (need + block_size > PACKET_MAX_SIZE) return SSH_ERR_INTERNAL_ERROR; return ssh_packet_start_discard(ssh, enc, mac, sshbuf_len(state->incoming_packet), - PACKET_MAX_SIZE - need); + PACKET_MAX_SIZE - need - block_size); } /* Remove MAC from input buffer */ DBG(debug("MAC #%d ok", state->p_read.seqnr)); diff --git a/regress/Makefile b/regress/Makefile index c2dba4fdf..b23496b98 100644 --- a/regress/Makefile +++ b/regress/Makefile @@ -222,6 +222,7 @@ unit: $$V ${.OBJDIR}/unittests/sshkey/test_sshkey \ -d ${.CURDIR}/unittests/sshkey/testdata ; \ $$V ${.OBJDIR}/unittests/bitmap/test_bitmap ; \ + $$V ${.OBJDIR}/unittests/conversion/test_conversion ; \ $$V ${.OBJDIR}/unittests/kex/test_kex ; \ $$V ${.OBJDIR}/unittests/hostkeys/test_hostkeys \ -d ${.CURDIR}/unittests/hostkeys/testdata ; \ diff --git a/regress/cert-file.sh b/regress/cert-file.sh index b184e7fea..43b8e0201 100644 --- a/regress/cert-file.sh +++ b/regress/cert-file.sh @@ -1,4 +1,4 @@ -# $OpenBSD: cert-file.sh,v 1.4 2016/12/16 02:48:55 djm Exp $ +# $OpenBSD: cert-file.sh,v 1.5 2017/03/11 23:44:16 djm Exp $ # Placed in the Public Domain. tid="ssh with certificates" @@ -17,24 +17,59 @@ ${SSHKEYGEN} -q -N '' -t ed25519 -f $OBJ/user_key1 || \ fatal "ssh-keygen failed" ${SSHKEYGEN} -q -N '' -t ed25519 -f $OBJ/user_key2 || \ fatal "ssh-keygen failed" +${SSHKEYGEN} -q -N '' -t ed25519 -f $OBJ/user_key3 || \ + fatal "ssh-keygen failed" +${SSHKEYGEN} -q -N '' -t ed25519 -f $OBJ/user_key4 || \ + fatal "ssh-keygen failed" +${SSHKEYGEN} -q -N '' -t ed25519 -f $OBJ/user_key5 || \ + fatal "ssh-keygen failed" + # Move the certificate to a different address to better control # when it is offered. ${SSHKEYGEN} -q -s $OBJ/user_ca_key1 -I "regress user key for $USER" \ -z $$ -n ${USER} $OBJ/user_key1 || - fail "couldn't sign user_key1 with user_ca_key1" + fatal "couldn't sign user_key1 with user_ca_key1" mv $OBJ/user_key1-cert.pub $OBJ/cert_user_key1_1.pub ${SSHKEYGEN} -q -s $OBJ/user_ca_key2 -I "regress user key for $USER" \ -z $$ -n ${USER} $OBJ/user_key1 || - fail "couldn't sign user_key1 with user_ca_key2" + fatal "couldn't sign user_key1 with user_ca_key2" mv $OBJ/user_key1-cert.pub $OBJ/cert_user_key1_2.pub +${SSHKEYGEN} -q -s $OBJ/user_ca_key1 -I "regress user key for $USER" \ + -z $$ -n ${USER} $OBJ/user_key3 || + fatal "couldn't sign user_key3 with user_ca_key1" +rm $OBJ/user_key3.pub # to test use of private key w/o public half. +${SSHKEYGEN} -q -s $OBJ/user_ca_key1 -I "regress user key for $USER" \ + -z $$ -n ${USER} $OBJ/user_key4 || + fatal "couldn't sign user_key4 with user_ca_key1" +rm $OBJ/user_key4 $OBJ/user_key4.pub # to test no matching pub/private key case. trace 'try with identity files' opts="-F $OBJ/ssh_proxy -oIdentitiesOnly=yes" opts2="$opts -i $OBJ/user_key1 -i $OBJ/user_key2" echo "cert-authority $(cat $OBJ/user_ca_key1.pub)" > $OBJ/authorized_keys_$USER +# Make a clean config that doesn't have any pre-added identities. +cat $OBJ/ssh_proxy | grep -v IdentityFile > $OBJ/no_identity_config + +# XXX: verify that certificate used was what we expect. Needs exposure of +# keys via enviornment variable or similar. + for p in ${SSH_PROTOCOLS}; do + # Key with no .pub should work - finding the equivalent *-cert.pub. + verbose "protocol $p: identity cert with no plain public file" + ${SSH} -F $OBJ/no_identity_config -oIdentitiesOnly=yes \ + -i $OBJ/user_key3 somehost exit 5$p + [ $? -ne 5$p ] && fail "ssh failed" + + # CertificateFile matching private key with no .pub file should work. + verbose "protocol $p: CertificateFile with no plain public file" + ${SSH} -F $OBJ/no_identity_config -oIdentitiesOnly=yes \ + -oCertificateFile=$OBJ/user_key3-cert.pub \ + -i $OBJ/user_key3 somehost exit 5$p + [ $? -ne 5$p ] && fail "ssh failed" + # Just keys should fail + verbose "protocol $p: plain keys" ${SSH} $opts2 somehost exit 5$p r=$? if [ $r -eq 5$p ]; then @@ -42,6 +77,7 @@ for p in ${SSH_PROTOCOLS}; do fi # Keys with untrusted cert should fail. + verbose "protocol $p: untrusted cert" opts3="$opts2 -oCertificateFile=$OBJ/cert_user_key1_2.pub" ${SSH} $opts3 somehost exit 5$p r=$? @@ -50,6 +86,7 @@ for p in ${SSH_PROTOCOLS}; do fi # Good cert with bad key should fail. + verbose "protocol $p: good cert, bad key" opts3="$opts -i $OBJ/user_key2" opts3="$opts3 -oCertificateFile=$OBJ/cert_user_key1_1.pub" ${SSH} $opts3 somehost exit 5$p @@ -59,6 +96,7 @@ for p in ${SSH_PROTOCOLS}; do fi # Keys with one trusted cert, should succeed. + verbose "protocol $p: single trusted" opts3="$opts2 -oCertificateFile=$OBJ/cert_user_key1_1.pub" ${SSH} $opts3 somehost exit 5$p r=$? @@ -67,6 +105,7 @@ for p in ${SSH_PROTOCOLS}; do fi # Multiple certs and keys, with one trusted cert, should succeed. + verbose "protocol $p: multiple trusted" opts3="$opts2 -oCertificateFile=$OBJ/cert_user_key1_2.pub" opts3="$opts3 -oCertificateFile=$OBJ/cert_user_key1_1.pub" ${SSH} $opts3 somehost exit 5$p @@ -74,14 +113,6 @@ for p in ${SSH_PROTOCOLS}; do if [ $r -ne 5$p ]; then fail "ssh failed with multiple certs in protocol $p" fi - - #Keys with trusted certificate specified in config options, should succeed. - opts3="$opts2 -oCertificateFile=$OBJ/cert_user_key1_1.pub" - ${SSH} $opts3 somehost exit 5$p - r=$? - if [ $r -ne 5$p ]; then - fail "ssh failed with trusted cert in config in protocol $p" - fi done #next, using an agent in combination with the keys diff --git a/regress/unittests/Makefile b/regress/unittests/Makefile index e70b16644..e975f6ca4 100644 --- a/regress/unittests/Makefile +++ b/regress/unittests/Makefile @@ -1,5 +1,6 @@ -# $OpenBSD: Makefile,v 1.7 2016/08/19 06:44:13 djm Exp $ -REGRESS_FAIL_EARLY= yes -SUBDIR= test_helper sshbuf sshkey bitmap kex hostkeys utf8 match +# $OpenBSD: Makefile,v 1.9 2017/03/14 01:20:29 dtucker Exp $ + +REGRESS_FAIL_EARLY?= yes +SUBDIR= test_helper sshbuf sshkey bitmap kex hostkeys utf8 match conversion .include diff --git a/regress/unittests/conversion/Makefile b/regress/unittests/conversion/Makefile new file mode 100644 index 000000000..cde97dc28 --- /dev/null +++ b/regress/unittests/conversion/Makefile @@ -0,0 +1,10 @@ +# $OpenBSD: Makefile,v 1.1 2017/03/14 01:20:29 dtucker Exp $ + +PROG=test_conversion +SRCS=tests.c +REGRESS_TARGETS=run-regress-${PROG} + +run-regress-${PROG}: ${PROG} + env ${TEST_ENV} ./${PROG} + +.include diff --git a/regress/unittests/conversion/tests.c b/regress/unittests/conversion/tests.c new file mode 100644 index 000000000..eaa96bb25 --- /dev/null +++ b/regress/unittests/conversion/tests.c @@ -0,0 +1,47 @@ +/* $OpenBSD: tests.c,v 1.1 2017/03/14 01:20:29 dtucker Exp $ */ +/* + * Regress test for conversions + * + * Placed in the public domain + */ + +#include +#include +#include +#include +#include +#include + +#include "../test_helper/test_helper.h" + +#include "misc.h" + +void +tests(void) +{ + char buf[1024]; + + TEST_START("conversion_convtime"); + ASSERT_LONG_EQ(convtime("0"), 0); + ASSERT_LONG_EQ(convtime("1"), 1); + ASSERT_LONG_EQ(convtime("1S"), 1); + /* from the examples in the comment above the function */ + ASSERT_LONG_EQ(convtime("90m"), 5400); + ASSERT_LONG_EQ(convtime("1h30m"), 5400); + ASSERT_LONG_EQ(convtime("2d"), 172800); + ASSERT_LONG_EQ(convtime("1w"), 604800); + + /* negative time is not allowed */ + ASSERT_LONG_EQ(convtime("-7"), -1); + ASSERT_LONG_EQ(convtime("-9d"), -1); + + /* overflow */ + snprintf(buf, sizeof buf, "%llu", (unsigned long long)LONG_MAX + 1); + ASSERT_LONG_EQ(convtime(buf), -1); + + /* overflow with multiplier */ + snprintf(buf, sizeof buf, "%lluM", (unsigned long long)LONG_MAX/60 + 1); + ASSERT_LONG_EQ(convtime(buf), -1); + ASSERT_LONG_EQ(convtime("1000000000000000000000w"), -1); + TEST_DONE(); +} diff --git a/regress/unittests/test_helper/test_helper.c b/regress/unittests/test_helper/test_helper.c index 26ca26b5e..f855137fb 100644 --- a/regress/unittests/test_helper/test_helper.c +++ b/regress/unittests/test_helper/test_helper.c @@ -1,4 +1,4 @@ -/* $OpenBSD: test_helper.c,v 1.6 2015/03/03 20:42:49 djm Exp $ */ +/* $OpenBSD: test_helper.c,v 1.7 2017/03/14 01:10:07 dtucker Exp $ */ /* * Copyright (c) 2011 Damien Miller * @@ -441,6 +441,17 @@ assert_u_int(const char *file, int line, const char *a1, const char *a2, test_die(); } +void +assert_long(const char *file, int line, const char *a1, const char *a2, + long aa1, long aa2, enum test_predicate pred) +{ + TEST_CHECK(aa1, aa2, pred); + test_header(file, line, a1, a2, "LONG", pred); + fprintf(stderr, "%12s = %ld / 0x%lx\n", a1, aa1, aa1); + fprintf(stderr, "%12s = %ld / 0x%lx\n", a2, aa2, aa2); + test_die(); +} + void assert_long_long(const char *file, int line, const char *a1, const char *a2, long long aa1, long long aa2, enum test_predicate pred) diff --git a/regress/unittests/test_helper/test_helper.h b/regress/unittests/test_helper/test_helper.h index 1d9c66986..615b7832b 100644 --- a/regress/unittests/test_helper/test_helper.h +++ b/regress/unittests/test_helper/test_helper.h @@ -1,4 +1,4 @@ -/* $OpenBSD: test_helper.h,v 1.6 2015/01/18 19:52:44 djm Exp $ */ +/* $OpenBSD: test_helper.h,v 1.7 2017/03/14 01:10:07 dtucker Exp $ */ /* * Copyright (c) 2011 Damien Miller * @@ -67,6 +67,9 @@ void assert_size_t(const char *file, int line, void assert_u_int(const char *file, int line, const char *a1, const char *a2, u_int aa1, u_int aa2, enum test_predicate pred); +void assert_long(const char *file, int line, + const char *a1, const char *a2, + long aa1, long aa2, enum test_predicate pred); void assert_long_long(const char *file, int line, const char *a1, const char *a2, long long aa1, long long aa2, enum test_predicate pred); @@ -110,6 +113,8 @@ void assert_u64(const char *file, int line, assert_size_t(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_EQ) #define ASSERT_U_INT_EQ(a1, a2) \ assert_u_int(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_EQ) +#define ASSERT_LONG_EQ(a1, a2) \ + assert_long(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_EQ) #define ASSERT_LONG_LONG_EQ(a1, a2) \ assert_long_long(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_EQ) #define ASSERT_CHAR_EQ(a1, a2) \ @@ -139,6 +144,8 @@ void assert_u64(const char *file, int line, assert_size_t(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_NE) #define ASSERT_U_INT_NE(a1, a2) \ assert_u_int(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_NE) +#define ASSERT_LONG_NE(a1, a2) \ + assert_long(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_NE) #define ASSERT_LONG_LONG_NE(a1, a2) \ assert_long_long(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_NE) #define ASSERT_CHAR_NE(a1, a2) \ @@ -166,6 +173,8 @@ void assert_u64(const char *file, int line, assert_size_t(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LT) #define ASSERT_U_INT_LT(a1, a2) \ assert_u_int(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LT) +#define ASSERT_LONG_LT(a1, a2) \ + assert_long(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LT) #define ASSERT_LONG_LONG_LT(a1, a2) \ assert_long_long(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LT) #define ASSERT_CHAR_LT(a1, a2) \ @@ -193,6 +202,8 @@ void assert_u64(const char *file, int line, assert_size_t(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LE) #define ASSERT_U_INT_LE(a1, a2) \ assert_u_int(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LE) +#define ASSERT_LONG_LE(a1, a2) \ + assert_long(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LE) #define ASSERT_LONG_LONG_LE(a1, a2) \ assert_long_long(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LE) #define ASSERT_CHAR_LE(a1, a2) \ @@ -220,6 +231,8 @@ void assert_u64(const char *file, int line, assert_size_t(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GT) #define ASSERT_U_INT_GT(a1, a2) \ assert_u_int(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GT) +#define ASSERT_LONG_GT(a1, a2) \ + assert_long(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GT) #define ASSERT_LONG_LONG_GT(a1, a2) \ assert_long_long(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GT) #define ASSERT_CHAR_GT(a1, a2) \ @@ -247,6 +260,8 @@ void assert_u64(const char *file, int line, assert_size_t(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GE) #define ASSERT_U_INT_GE(a1, a2) \ assert_u_int(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GE) +#define ASSERT_LONG_GE(a1, a2) \ + assert_long(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GE) #define ASSERT_LONG_LONG_GE(a1, a2) \ assert_long_long(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GE) #define ASSERT_CHAR_GE(a1, a2) \ diff --git a/sandbox-seccomp-filter.c b/sandbox-seccomp-filter.c index 2e1ed2c52..3a1aedce7 100644 --- a/sandbox-seccomp-filter.c +++ b/sandbox-seccomp-filter.c @@ -73,19 +73,35 @@ # define SECCOMP_FILTER_FAIL SECCOMP_RET_TRAP #endif /* SANDBOX_SECCOMP_FILTER_DEBUG */ +#if __BYTE_ORDER == __LITTLE_ENDIAN +# define ARG_LO_OFFSET 0 +# define ARG_HI_OFFSET sizeof(uint32_t) +#elif __BYTE_ORDER == __BIG_ENDIAN +# define ARG_LO_OFFSET sizeof(uint32_t) +# define ARG_HI_OFFSET 0 +#else +#error "Unknown endianness" +#endif + /* Simple helpers to avoid manual errors (but larger BPF programs). */ #define SC_DENY(_nr, _errno) \ - BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_ ## _nr, 0, 1), \ + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (_nr), 0, 1), \ BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ERRNO|(_errno)) #define SC_ALLOW(_nr) \ - BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_ ## _nr, 0, 1), \ + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (_nr), 0, 1), \ BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW) #define SC_ALLOW_ARG(_nr, _arg_nr, _arg_val) \ - BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_ ## _nr, 0, 4), \ - /* load first syscall argument */ \ + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (_nr), 0, 6), \ + /* load and test first syscall argument, low word */ \ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, \ - offsetof(struct seccomp_data, args[(_arg_nr)])), \ - BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (_arg_val), 0, 1), \ + offsetof(struct seccomp_data, args[(_arg_nr)]) + ARG_LO_OFFSET), \ + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, \ + ((_arg_val) & 0xFFFFFFFF), 0, 3), \ + /* load and test first syscall argument, high word */ \ + BPF_STMT(BPF_LD+BPF_W+BPF_ABS, \ + offsetof(struct seccomp_data, args[(_arg_nr)]) + ARG_HI_OFFSET), \ + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, \ + (((uint32_t)((uint64_t)(_arg_val) >> 32)) & 0xFFFFFFFF), 0, 1), \ BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW), \ /* reload syscall number; all rules expect it in accumulator */ \ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, \ @@ -104,108 +120,122 @@ static const struct sock_filter preauth_insns[] = { /* Syscalls to non-fatally deny */ #ifdef __NR_lstat - SC_DENY(lstat, EACCES), + SC_DENY(__NR_lstat, EACCES), #endif #ifdef __NR_lstat64 - SC_DENY(lstat64, EACCES), + SC_DENY(__NR_lstat64, EACCES), #endif #ifdef __NR_fstat - SC_DENY(fstat, EACCES), + SC_DENY(__NR_fstat, EACCES), #endif #ifdef __NR_fstat64 - SC_DENY(fstat64, EACCES), + SC_DENY(__NR_fstat64, EACCES), #endif #ifdef __NR_open - SC_DENY(open, EACCES), + SC_DENY(__NR_open, EACCES), #endif #ifdef __NR_openat - SC_DENY(openat, EACCES), + SC_DENY(__NR_openat, EACCES), #endif #ifdef __NR_newfstatat - SC_DENY(newfstatat, EACCES), + SC_DENY(__NR_newfstatat, EACCES), #endif #ifdef __NR_stat - SC_DENY(stat, EACCES), + SC_DENY(__NR_stat, EACCES), #endif #ifdef __NR_stat64 - SC_DENY(stat64, EACCES), + SC_DENY(__NR_stat64, EACCES), #endif /* Syscalls to permit */ #ifdef __NR_brk - SC_ALLOW(brk), + SC_ALLOW(__NR_brk), #endif #ifdef __NR_clock_gettime - SC_ALLOW(clock_gettime), + SC_ALLOW(__NR_clock_gettime), #endif #ifdef __NR_close - SC_ALLOW(close), + SC_ALLOW(__NR_close), #endif #ifdef __NR_exit - SC_ALLOW(exit), + SC_ALLOW(__NR_exit), #endif #ifdef __NR_exit_group - SC_ALLOW(exit_group), + SC_ALLOW(__NR_exit_group), #endif #ifdef __NR_getpgid - SC_ALLOW(getpgid), + SC_ALLOW(__NR_getpgid), #endif #ifdef __NR_getpid - SC_ALLOW(getpid), + SC_ALLOW(__NR_getpid), #endif #ifdef __NR_getrandom - SC_ALLOW(getrandom), + SC_ALLOW(__NR_getrandom), #endif #ifdef __NR_gettimeofday - SC_ALLOW(gettimeofday), + SC_ALLOW(__NR_gettimeofday), #endif #ifdef __NR_madvise - SC_ALLOW(madvise), + SC_ALLOW(__NR_madvise), #endif #ifdef __NR_mmap - SC_ALLOW(mmap), + SC_ALLOW(__NR_mmap), #endif #ifdef __NR_mmap2 - SC_ALLOW(mmap2), + SC_ALLOW(__NR_mmap2), #endif #ifdef __NR_mremap - SC_ALLOW(mremap), + SC_ALLOW(__NR_mremap), #endif #ifdef __NR_munmap - SC_ALLOW(munmap), + SC_ALLOW(__NR_munmap), #endif #ifdef __NR__newselect - SC_ALLOW(_newselect), + SC_ALLOW(__NR__newselect), #endif #ifdef __NR_poll - SC_ALLOW(poll), + SC_ALLOW(__NR_poll), #endif #ifdef __NR_pselect6 - SC_ALLOW(pselect6), + SC_ALLOW(__NR_pselect6), #endif #ifdef __NR_read - SC_ALLOW(read), + SC_ALLOW(__NR_read), #endif #ifdef __NR_rt_sigprocmask - SC_ALLOW(rt_sigprocmask), + SC_ALLOW(__NR_rt_sigprocmask), #endif #ifdef __NR_select - SC_ALLOW(select), + SC_ALLOW(__NR_select), #endif #ifdef __NR_shutdown - SC_ALLOW(shutdown), + SC_ALLOW(__NR_shutdown), #endif #ifdef __NR_sigprocmask - SC_ALLOW(sigprocmask), + SC_ALLOW(__NR_sigprocmask), #endif #ifdef __NR_time - SC_ALLOW(time), + SC_ALLOW(__NR_time), #endif #ifdef __NR_write - SC_ALLOW(write), + SC_ALLOW(__NR_write), #endif #ifdef __NR_socketcall - SC_ALLOW_ARG(socketcall, 0, SYS_SHUTDOWN), + SC_ALLOW_ARG(__NR_socketcall, 0, SYS_SHUTDOWN), +#endif +#if defined(__NR_ioctl) && defined(__s390__) + /* Allow ioctls for ICA crypto card on s390 */ + SC_ALLOW_ARG(__NR_ioctl, 1, Z90STAT_STATUS_MASK), + SC_ALLOW_ARG(__NR_ioctl, 1, ICARSAMODEXPO), + SC_ALLOW_ARG(__NR_ioctl, 1, ICARSACRT), +#endif +#if defined(__x86_64__) && defined(__ILP32__) && defined(__X32_SYSCALL_BIT) + /* + * On Linux x32, the clock_gettime VDSO falls back to the + * x86-64 syscall under some circumstances, e.g. + * https://bugs.debian.org/849923 + */ + SC_ALLOW(__NR_clock_gettime & ~__X32_SYSCALL_BIT); #endif /* Default deny */ diff --git a/sshconnect2.c b/sshconnect2.c index a671ffaeb..28e5a02a8 100644 --- a/sshconnect2.c +++ b/sshconnect2.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshconnect2.c,v 1.254 2017/02/03 02:56:00 dtucker Exp $ */ +/* $OpenBSD: sshconnect2.c,v 1.255 2017/03/11 23:40:26 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2008 Damien Miller. All rights reserved. @@ -1001,11 +1001,11 @@ input_userauth_passwd_changereq(int type, u_int32_t seqnr, void *ctxt) } static const char * -identity_sign_encode(struct identity *id) +key_sign_encode(const struct sshkey *key) { struct ssh *ssh = active_state; - if (id->key->type == KEY_RSA) { + if (key->type == KEY_RSA) { switch (ssh->kex->rsa_sha2) { case 256: return "rsa-sha2-256"; @@ -1013,7 +1013,7 @@ identity_sign_encode(struct identity *id) return "rsa-sha2-512"; } } - return key_ssh_name(id->key); + return key_ssh_name(key); } static int @@ -1022,30 +1022,49 @@ identity_sign(struct identity *id, u_char **sigp, size_t *lenp, { Key *prv; int ret; - const char *alg; - - alg = identity_sign_encode(id); /* the agent supports this key */ - if (id->agent_fd != -1) + if (id->key != NULL && id->agent_fd != -1) return ssh_agent_sign(id->agent_fd, id->key, sigp, lenp, - data, datalen, alg, compat); + data, datalen, key_sign_encode(id->key), compat); /* * we have already loaded the private key or * the private key is stored in external hardware */ - if (id->isprivate || (id->key->flags & SSHKEY_FLAG_EXT)) - return (sshkey_sign(id->key, sigp, lenp, data, datalen, alg, - compat)); + if (id->key != NULL && + (id->isprivate || (id->key->flags & SSHKEY_FLAG_EXT))) + return (sshkey_sign(id->key, sigp, lenp, data, datalen, + key_sign_encode(id->key), compat)); + /* load the private key from the file */ if ((prv = load_identity_file(id)) == NULL) return SSH_ERR_KEY_NOT_FOUND; - ret = sshkey_sign(prv, sigp, lenp, data, datalen, alg, compat); + ret = sshkey_sign(prv, sigp, lenp, data, datalen, + key_sign_encode(prv), compat); sshkey_free(prv); return (ret); } +static int +id_filename_matches(Identity *id, Identity *private_id) +{ + const char *suffixes[] = { ".pub", "-cert.pub", NULL }; + size_t len = strlen(id->filename), plen = strlen(private_id->filename); + size_t i, slen; + + if (strcmp(id->filename, private_id->filename) == 0) + return 1; + for (i = 0; suffixes[i]; i++) { + slen = strlen(suffixes[i]); + if (len > slen && plen == len - slen && + strcmp(id->filename + (len - slen), suffixes[i]) == 0 && + memcmp(id->filename, private_id->filename, plen) == 0) + return 1; + } + return 0; +} + static int sign_and_send_pubkey(Authctxt *authctxt, Identity *id) { @@ -1088,7 +1107,7 @@ sign_and_send_pubkey(Authctxt *authctxt, Identity *id) } else { buffer_put_cstring(&b, authctxt->method->name); buffer_put_char(&b, have_sig); - buffer_put_cstring(&b, identity_sign_encode(id)); + buffer_put_cstring(&b, key_sign_encode(id->key)); } buffer_put_string(&b, blob, bloblen); @@ -1108,6 +1127,24 @@ sign_and_send_pubkey(Authctxt *authctxt, Identity *id) break; } } + /* + * Exact key matches are preferred, but also allow + * filename matches for non-PKCS#11/agent keys that + * didn't load public keys. This supports the case + * of keeping just a private key file and public + * certificate on disk. + */ + if (!matched && !id->isprivate && id->agent_fd == -1 && + (id->key->flags & SSHKEY_FLAG_EXT) == 0) { + TAILQ_FOREACH(private_id, &authctxt->keys, next) { + if (private_id->key == NULL && + id_filename_matches(id, private_id)) { + id = private_id; + matched = 1; + break; + } + } + } if (matched) { debug2("%s: using private key \"%s\"%s for " "certificate", __func__, id->filename, @@ -1186,7 +1223,7 @@ send_pubkey_test(Authctxt *authctxt, Identity *id) packet_put_cstring(authctxt->method->name); packet_put_char(have_sig); if (!(datafellows & SSH_BUG_PKAUTH)) - packet_put_cstring(identity_sign_encode(id)); + packet_put_cstring(key_sign_encode(id->key)); packet_put_string(blob, bloblen); free(blob); packet_send();