Fix patch(1) shell injection vulnerability. [SA-15:14]
Fix resource exhaustion in TCP reassembly. [SA-15:15] Fix OpenSSH multiple vulnerabilities. [SA-15:16]
This commit is contained in:
parent
87ad559404
commit
d3ecbb9019
@ -82,6 +82,7 @@ struct KbdintAuthctxt
|
||||
void *ctxt;
|
||||
KbdintDevice *device;
|
||||
u_int nreq;
|
||||
u_int devices_done;
|
||||
};
|
||||
|
||||
#ifdef USE_PAM
|
||||
@ -168,11 +169,15 @@ kbdint_next_device(Authctxt *authctxt, KbdintAuthctxt *kbdintctxt)
|
||||
if (len == 0)
|
||||
break;
|
||||
for (i = 0; devices[i]; i++) {
|
||||
if (!auth2_method_allowed(authctxt,
|
||||
if ((kbdintctxt->devices_done & (1 << i)) != 0 ||
|
||||
!auth2_method_allowed(authctxt,
|
||||
"keyboard-interactive", devices[i]->name))
|
||||
continue;
|
||||
if (strncmp(kbdintctxt->devices, devices[i]->name, len) == 0)
|
||||
if (strncmp(kbdintctxt->devices, devices[i]->name,
|
||||
len) == 0) {
|
||||
kbdintctxt->device = devices[i];
|
||||
kbdintctxt->devices_done |= 1 << i;
|
||||
}
|
||||
}
|
||||
t = kbdintctxt->devices;
|
||||
kbdintctxt->devices = t[len] ? xstrdup(t+len+1) : NULL;
|
||||
|
@ -1246,29 +1246,39 @@ verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
|
||||
{
|
||||
int flags = 0;
|
||||
char *fp;
|
||||
Key *plain = NULL;
|
||||
|
||||
fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
|
||||
debug("Server host key: %s %s", key_type(host_key), fp);
|
||||
free(fp);
|
||||
|
||||
/* XXX certs are not yet supported for DNS */
|
||||
if (!key_is_cert(host_key) && options.verify_host_key_dns &&
|
||||
verify_host_key_dns(host, hostaddr, host_key, &flags) == 0) {
|
||||
if (flags & DNS_VERIFY_FOUND) {
|
||||
|
||||
if (options.verify_host_key_dns == 1 &&
|
||||
flags & DNS_VERIFY_MATCH &&
|
||||
flags & DNS_VERIFY_SECURE)
|
||||
return 0;
|
||||
|
||||
if (flags & DNS_VERIFY_MATCH) {
|
||||
matching_host_key_dns = 1;
|
||||
} else {
|
||||
warn_changed_key(host_key);
|
||||
error("Update the SSHFP RR in DNS with the new "
|
||||
"host key to get rid of this message.");
|
||||
if (options.verify_host_key_dns) {
|
||||
/*
|
||||
* XXX certs are not yet supported for DNS, so downgrade
|
||||
* them and try the plain key.
|
||||
*/
|
||||
plain = key_from_private(host_key);
|
||||
if (key_is_cert(plain))
|
||||
key_drop_cert(plain);
|
||||
if (verify_host_key_dns(host, hostaddr, plain, &flags) == 0) {
|
||||
if (flags & DNS_VERIFY_FOUND) {
|
||||
if (options.verify_host_key_dns == 1 &&
|
||||
flags & DNS_VERIFY_MATCH &&
|
||||
flags & DNS_VERIFY_SECURE) {
|
||||
key_free(plain);
|
||||
return 0;
|
||||
}
|
||||
if (flags & DNS_VERIFY_MATCH) {
|
||||
matching_host_key_dns = 1;
|
||||
} else {
|
||||
warn_changed_key(plain);
|
||||
error("Update the SSHFP RR in DNS "
|
||||
"with the new host key to get rid "
|
||||
"of this message.");
|
||||
}
|
||||
}
|
||||
}
|
||||
key_free(plain);
|
||||
}
|
||||
|
||||
return check_host_key(host, hostaddr, options.port, host_key, RDRW,
|
||||
|
@ -79,25 +79,22 @@ static int tcp_reass_sysctl_qsize(SYSCTL_HANDLER_ARGS);
|
||||
static SYSCTL_NODE(_net_inet_tcp, OID_AUTO, reass, CTLFLAG_RW, 0,
|
||||
"TCP Segment Reassembly Queue");
|
||||
|
||||
static VNET_DEFINE(int, tcp_reass_maxseg) = 0;
|
||||
#define V_tcp_reass_maxseg VNET(tcp_reass_maxseg)
|
||||
SYSCTL_VNET_INT(_net_inet_tcp_reass, OID_AUTO, maxsegments, CTLFLAG_RDTUN,
|
||||
&VNET_NAME(tcp_reass_maxseg), 0,
|
||||
static int tcp_reass_maxseg = 0;
|
||||
SYSCTL_INT(_net_inet_tcp_reass, OID_AUTO, maxsegments, CTLFLAG_RDTUN,
|
||||
&tcp_reass_maxseg, 0,
|
||||
"Global maximum number of TCP Segments in Reassembly Queue");
|
||||
|
||||
SYSCTL_VNET_PROC(_net_inet_tcp_reass, OID_AUTO, cursegments,
|
||||
SYSCTL_PROC(_net_inet_tcp_reass, OID_AUTO, cursegments,
|
||||
(CTLTYPE_INT | CTLFLAG_RD), NULL, 0, &tcp_reass_sysctl_qsize, "I",
|
||||
"Global number of TCP Segments currently in Reassembly Queue");
|
||||
|
||||
static VNET_DEFINE(int, tcp_reass_overflows) = 0;
|
||||
#define V_tcp_reass_overflows VNET(tcp_reass_overflows)
|
||||
SYSCTL_VNET_INT(_net_inet_tcp_reass, OID_AUTO, overflows,
|
||||
static int tcp_reass_overflows = 0;
|
||||
SYSCTL_INT(_net_inet_tcp_reass, OID_AUTO, overflows,
|
||||
CTLFLAG_RD,
|
||||
&VNET_NAME(tcp_reass_overflows), 0,
|
||||
&tcp_reass_overflows, 0,
|
||||
"Global number of TCP Segment Reassembly Queue Overflows");
|
||||
|
||||
static VNET_DEFINE(uma_zone_t, tcp_reass_zone);
|
||||
#define V_tcp_reass_zone VNET(tcp_reass_zone)
|
||||
static uma_zone_t tcp_reass_zone;
|
||||
|
||||
/* Initialize TCP reassembly queue */
|
||||
static void
|
||||
@ -105,36 +102,27 @@ tcp_reass_zone_change(void *tag)
|
||||
{
|
||||
|
||||
/* Set the zone limit and read back the effective value. */
|
||||
V_tcp_reass_maxseg = nmbclusters / 16;
|
||||
V_tcp_reass_maxseg = uma_zone_set_max(V_tcp_reass_zone,
|
||||
V_tcp_reass_maxseg);
|
||||
tcp_reass_maxseg = nmbclusters / 16;
|
||||
tcp_reass_maxseg = uma_zone_set_max(tcp_reass_zone,
|
||||
tcp_reass_maxseg);
|
||||
}
|
||||
|
||||
void
|
||||
tcp_reass_init(void)
|
||||
tcp_reass_global_init(void)
|
||||
{
|
||||
|
||||
V_tcp_reass_maxseg = nmbclusters / 16;
|
||||
tcp_reass_maxseg = nmbclusters / 16;
|
||||
TUNABLE_INT_FETCH("net.inet.tcp.reass.maxsegments",
|
||||
&V_tcp_reass_maxseg);
|
||||
V_tcp_reass_zone = uma_zcreate("tcpreass", sizeof (struct tseg_qent),
|
||||
&tcp_reass_maxseg);
|
||||
tcp_reass_zone = uma_zcreate("tcpreass", sizeof (struct tseg_qent),
|
||||
NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
|
||||
/* Set the zone limit and read back the effective value. */
|
||||
V_tcp_reass_maxseg = uma_zone_set_max(V_tcp_reass_zone,
|
||||
V_tcp_reass_maxseg);
|
||||
tcp_reass_maxseg = uma_zone_set_max(tcp_reass_zone,
|
||||
tcp_reass_maxseg);
|
||||
EVENTHANDLER_REGISTER(nmbclusters_change,
|
||||
tcp_reass_zone_change, NULL, EVENTHANDLER_PRI_ANY);
|
||||
}
|
||||
|
||||
#ifdef VIMAGE
|
||||
void
|
||||
tcp_reass_destroy(void)
|
||||
{
|
||||
|
||||
uma_zdestroy(V_tcp_reass_zone);
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
tcp_reass_flush(struct tcpcb *tp)
|
||||
{
|
||||
@ -145,7 +133,7 @@ tcp_reass_flush(struct tcpcb *tp)
|
||||
while ((qe = LIST_FIRST(&tp->t_segq)) != NULL) {
|
||||
LIST_REMOVE(qe, tqe_q);
|
||||
m_freem(qe->tqe_m);
|
||||
uma_zfree(V_tcp_reass_zone, qe);
|
||||
uma_zfree(tcp_reass_zone, qe);
|
||||
tp->t_segqlen--;
|
||||
}
|
||||
|
||||
@ -159,7 +147,7 @@ tcp_reass_sysctl_qsize(SYSCTL_HANDLER_ARGS)
|
||||
{
|
||||
int qsize;
|
||||
|
||||
qsize = uma_zone_get_cur(V_tcp_reass_zone);
|
||||
qsize = uma_zone_get_cur(tcp_reass_zone);
|
||||
return (sysctl_handle_int(oidp, &qsize, 0, req));
|
||||
}
|
||||
|
||||
@ -207,7 +195,7 @@ tcp_reass(struct tcpcb *tp, struct tcphdr *th, int *tlenp, struct mbuf *m)
|
||||
*/
|
||||
if ((th->th_seq != tp->rcv_nxt || !TCPS_HAVEESTABLISHED(tp->t_state)) &&
|
||||
tp->t_segqlen >= (so->so_rcv.sb_hiwat / tp->t_maxseg) + 1) {
|
||||
V_tcp_reass_overflows++;
|
||||
tcp_reass_overflows++;
|
||||
TCPSTAT_INC(tcps_rcvmemdrop);
|
||||
m_freem(m);
|
||||
*tlenp = 0;
|
||||
@ -226,7 +214,7 @@ tcp_reass(struct tcpcb *tp, struct tcphdr *th, int *tlenp, struct mbuf *m)
|
||||
* Use a temporary structure on the stack for the missing segment
|
||||
* when the zone is exhausted. Otherwise we may get stuck.
|
||||
*/
|
||||
te = uma_zalloc(V_tcp_reass_zone, M_NOWAIT);
|
||||
te = uma_zalloc(tcp_reass_zone, M_NOWAIT);
|
||||
if (te == NULL) {
|
||||
if (th->th_seq != tp->rcv_nxt || !TCPS_HAVEESTABLISHED(tp->t_state)) {
|
||||
TCPSTAT_INC(tcps_rcvmemdrop);
|
||||
@ -277,7 +265,7 @@ tcp_reass(struct tcpcb *tp, struct tcphdr *th, int *tlenp, struct mbuf *m)
|
||||
TCPSTAT_ADD(tcps_rcvdupbyte, *tlenp);
|
||||
m_freem(m);
|
||||
if (te != &tqs)
|
||||
uma_zfree(V_tcp_reass_zone, te);
|
||||
uma_zfree(tcp_reass_zone, te);
|
||||
tp->t_segqlen--;
|
||||
/*
|
||||
* Try to present any queued data
|
||||
@ -314,7 +302,7 @@ tcp_reass(struct tcpcb *tp, struct tcphdr *th, int *tlenp, struct mbuf *m)
|
||||
nq = LIST_NEXT(q, tqe_q);
|
||||
LIST_REMOVE(q, tqe_q);
|
||||
m_freem(q->tqe_m);
|
||||
uma_zfree(V_tcp_reass_zone, q);
|
||||
uma_zfree(tcp_reass_zone, q);
|
||||
tp->t_segqlen--;
|
||||
q = nq;
|
||||
}
|
||||
@ -353,7 +341,7 @@ present:
|
||||
else
|
||||
sbappendstream_locked(&so->so_rcv, q->tqe_m);
|
||||
if (q != &tqs)
|
||||
uma_zfree(V_tcp_reass_zone, q);
|
||||
uma_zfree(tcp_reass_zone, q);
|
||||
tp->t_segqlen--;
|
||||
q = nq;
|
||||
} while (q && q->tqe_th->th_seq == tp->rcv_nxt);
|
||||
|
@ -376,7 +376,6 @@ tcp_init(void)
|
||||
tcp_tw_init();
|
||||
syncache_init();
|
||||
tcp_hc_init();
|
||||
tcp_reass_init();
|
||||
|
||||
TUNABLE_INT_FETCH("net.inet.tcp.sack.enable", &V_tcp_do_sack);
|
||||
V_sack_hole_zone = uma_zcreate("sackhole", sizeof(struct sackhole),
|
||||
@ -386,6 +385,8 @@ tcp_init(void)
|
||||
if (!IS_DEFAULT_VNET(curvnet))
|
||||
return;
|
||||
|
||||
tcp_reass_global_init();
|
||||
|
||||
/* XXX virtualize those bellow? */
|
||||
tcp_delacktime = TCPTV_DELACK;
|
||||
tcp_keepinit = TCPTV_KEEP_INIT;
|
||||
@ -433,7 +434,6 @@ void
|
||||
tcp_destroy(void)
|
||||
{
|
||||
|
||||
tcp_reass_destroy();
|
||||
tcp_hc_destroy();
|
||||
syncache_destroy();
|
||||
tcp_tw_destroy();
|
||||
|
@ -679,11 +679,8 @@ char *tcp_log_addrs(struct in_conninfo *, struct tcphdr *, void *,
|
||||
char *tcp_log_vain(struct in_conninfo *, struct tcphdr *, void *,
|
||||
const void *);
|
||||
int tcp_reass(struct tcpcb *, struct tcphdr *, int *, struct mbuf *);
|
||||
void tcp_reass_init(void);
|
||||
void tcp_reass_global_init(void);
|
||||
void tcp_reass_flush(struct tcpcb *);
|
||||
#ifdef VIMAGE
|
||||
void tcp_reass_destroy(void);
|
||||
#endif
|
||||
void tcp_input(struct mbuf *, int);
|
||||
u_long tcp_maxmtu(struct in_conninfo *, struct tcp_ifcap *);
|
||||
u_long tcp_maxmtu6(struct in_conninfo *, struct tcp_ifcap *);
|
||||
|
@ -43,12 +43,10 @@
|
||||
#define LINENUM_MAX LONG_MAX
|
||||
|
||||
#define SCCSPREFIX "s."
|
||||
#define GET "get -e %s"
|
||||
#define SCCSDIFF "get -p %s | diff - %s >/dev/null"
|
||||
|
||||
#define RCSSUFFIX ",v"
|
||||
#define CHECKOUT "co -l %s"
|
||||
#define RCSDIFF "rcsdiff %s > /dev/null"
|
||||
#define CHECKOUT "/usr/bin/co"
|
||||
#define RCSDIFF "/usr/bin/rcsdiff"
|
||||
|
||||
#define ORIGEXT ".orig"
|
||||
#define REJEXT ".rej"
|
||||
|
@ -31,8 +31,10 @@
|
||||
#include <sys/file.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <libgen.h>
|
||||
#include <limits.h>
|
||||
#include <stddef.h>
|
||||
@ -132,12 +134,14 @@ reallocate_lines(size_t *lines_allocated)
|
||||
static bool
|
||||
plan_a(const char *filename)
|
||||
{
|
||||
int ifd, statfailed;
|
||||
int ifd, statfailed, devnull, pstat;
|
||||
char *p, *s, lbuf[INITLINELEN];
|
||||
struct stat filestat;
|
||||
ptrdiff_t sz;
|
||||
size_t i;
|
||||
size_t iline, lines_allocated;
|
||||
pid_t pid;
|
||||
char *argp[4] = {NULL};
|
||||
|
||||
#ifdef DEBUGGING
|
||||
if (debug & 8)
|
||||
@ -165,13 +169,14 @@ plan_a(const char *filename)
|
||||
}
|
||||
if (statfailed && check_only)
|
||||
fatal("%s not found, -C mode, can't probe further\n", filename);
|
||||
/* For nonexistent or read-only files, look for RCS or SCCS versions. */
|
||||
/* For nonexistent or read-only files, look for RCS versions. */
|
||||
|
||||
if (statfailed ||
|
||||
/* No one can write to it. */
|
||||
(filestat.st_mode & 0222) == 0 ||
|
||||
/* I can't write to it. */
|
||||
((filestat.st_mode & 0022) == 0 && filestat.st_uid != getuid())) {
|
||||
const char *cs = NULL, *filebase, *filedir;
|
||||
char *filebase, *filedir;
|
||||
struct stat cstat;
|
||||
char *tmp_filename1, *tmp_filename2;
|
||||
|
||||
@ -179,43 +184,26 @@ plan_a(const char *filename)
|
||||
tmp_filename2 = strdup(filename);
|
||||
if (tmp_filename1 == NULL || tmp_filename2 == NULL)
|
||||
fatal("strdupping filename");
|
||||
|
||||
filebase = basename(tmp_filename1);
|
||||
filedir = dirname(tmp_filename2);
|
||||
|
||||
/* Leave room in lbuf for the diff command. */
|
||||
s = lbuf + 20;
|
||||
|
||||
#define try(f, a1, a2, a3) \
|
||||
(snprintf(s, buf_size - 20, f, a1, a2, a3), stat(s, &cstat) == 0)
|
||||
|
||||
if (try("%s/RCS/%s%s", filedir, filebase, RCSSUFFIX) ||
|
||||
try("%s/RCS/%s%s", filedir, filebase, "") ||
|
||||
try("%s/%s%s", filedir, filebase, RCSSUFFIX)) {
|
||||
snprintf(buf, buf_size, CHECKOUT, filename);
|
||||
snprintf(lbuf, sizeof lbuf, RCSDIFF, filename);
|
||||
cs = "RCS";
|
||||
} else if (try("%s/SCCS/%s%s", filedir, SCCSPREFIX, filebase) ||
|
||||
try("%s/%s%s", filedir, SCCSPREFIX, filebase)) {
|
||||
snprintf(buf, buf_size, GET, s);
|
||||
snprintf(lbuf, sizeof lbuf, SCCSDIFF, s, filename);
|
||||
cs = "SCCS";
|
||||
} else if (statfailed)
|
||||
fatal("can't find %s\n", filename);
|
||||
|
||||
free(tmp_filename1);
|
||||
free(tmp_filename2);
|
||||
(snprintf(lbuf, sizeof(lbuf), f, a1, a2, a3), stat(lbuf, &cstat) == 0)
|
||||
|
||||
/*
|
||||
* else we can't write to it but it's not under a version
|
||||
* control system, so just proceed.
|
||||
*/
|
||||
if (cs) {
|
||||
if (try("%s/RCS/%s%s", filedir, filebase, RCSSUFFIX) ||
|
||||
try("%s/RCS/%s%s", filedir, filebase, "") ||
|
||||
try("%s/%s%s", filedir, filebase, RCSSUFFIX)) {
|
||||
if (!statfailed) {
|
||||
if ((filestat.st_mode & 0222) != 0)
|
||||
/* The owner can write to it. */
|
||||
fatal("file %s seems to be locked "
|
||||
"by somebody else under %s\n",
|
||||
filename, cs);
|
||||
"by somebody else under RCS\n",
|
||||
filename);
|
||||
/*
|
||||
* It might be checked out unlocked. See if
|
||||
* it's safe to check out the default version
|
||||
@ -223,21 +211,59 @@ plan_a(const char *filename)
|
||||
*/
|
||||
if (verbose)
|
||||
say("Comparing file %s to default "
|
||||
"%s version...\n",
|
||||
filename, cs);
|
||||
if (system(lbuf))
|
||||
"RCS version...\n", filename);
|
||||
|
||||
switch (pid = fork()) {
|
||||
case -1:
|
||||
fatal("can't fork: %s\n",
|
||||
strerror(errno));
|
||||
case 0:
|
||||
devnull = open("/dev/null", O_RDONLY);
|
||||
if (devnull == -1) {
|
||||
fatal("can't open /dev/null: %s",
|
||||
strerror(errno));
|
||||
}
|
||||
(void)dup2(devnull, STDOUT_FILENO);
|
||||
argp[0] = strdup(RCSDIFF);
|
||||
argp[1] = strdup(filename);
|
||||
execv(RCSDIFF, argp);
|
||||
exit(127);
|
||||
}
|
||||
pid = waitpid(pid, &pstat, 0);
|
||||
if (pid == -1 || WEXITSTATUS(pstat) != 0) {
|
||||
fatal("can't check out file %s: "
|
||||
"differs from default %s version\n",
|
||||
filename, cs);
|
||||
"differs from default RCS version\n",
|
||||
filename);
|
||||
}
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
say("Checking out file %s from %s...\n",
|
||||
filename, cs);
|
||||
if (system(buf) || stat(filename, &filestat))
|
||||
fatal("can't check out file %s from %s\n",
|
||||
filename, cs);
|
||||
say("Checking out file %s from RCS...\n",
|
||||
filename);
|
||||
|
||||
switch (pid = fork()) {
|
||||
case -1:
|
||||
fatal("can't fork: %s\n", strerror(errno));
|
||||
case 0:
|
||||
argp[0] = strdup(CHECKOUT);
|
||||
argp[1] = strdup("-l");
|
||||
argp[2] = strdup(filename);
|
||||
execv(CHECKOUT, argp);
|
||||
exit(127);
|
||||
}
|
||||
pid = waitpid(pid, &pstat, 0);
|
||||
if (pid == -1 || WEXITSTATUS(pstat) != 0 ||
|
||||
stat(filename, &filestat)) {
|
||||
fatal("can't check out file %s from RCS\n",
|
||||
filename);
|
||||
}
|
||||
} else if (statfailed) {
|
||||
fatal("can't find %s\n", filename);
|
||||
}
|
||||
free(tmp_filename1);
|
||||
free(tmp_filename2);
|
||||
}
|
||||
|
||||
filemode = filestat.st_mode;
|
||||
if (!S_ISREG(filemode))
|
||||
fatal("%s is not a normal file--can't patch\n", filename);
|
||||
|
Loading…
x
Reference in New Issue
Block a user