From c5ce870ef3f5ab1593349511574b3f041a00fed5 Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Thu, 4 Jul 2002 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 2002-07-04 --- ip/ethermedium.c | 13 ++++++++---- ip/tcp.c | 51 ++++++++++++++++++++++++++-------------------- port/devrealtime.c | 24 ++++++++++++---------- port/edf.c | 36 ++++++++++++++++++++++---------- port/edf.h | 8 ++++---- port/nulledf.c | 45 ++++++++++++++++++++++++++++++++++------ port/portclock.c | 2 +- port/portdat.h | 16 +++++++++++++++ port/portfns.h | 12 ----------- port/proc.c | 32 ++++++++++++++++------------- port/qlock.c | 12 +++++------ port/sysproc.c | 4 ++-- 12 files changed, 162 insertions(+), 93 deletions(-) diff --git a/ip/ethermedium.c b/ip/ethermedium.c index 2d736d610b70b3a3bc5c4d622c9f26b171afe318..b8afe066c5bc7a5bcaafb8f9b144329988a296d3 100644 --- a/ip/ethermedium.c +++ b/ip/ethermedium.c @@ -115,7 +115,7 @@ struct Etherarp static void etherbind(Ipifc *ifc, int argc, char **argv) { - Chan *mchan4, *cchan4, *achan, *mchan6, *cchan6; + Chan *mchan4, *cchan4, *achan, *mchan6, *cchan6, *schan; char addr[Maxpath]; //char addr[2*KNAMELEN]; char dir[Maxpath]; //char dir[2*KNAMELEN]; char *buf; @@ -158,9 +158,14 @@ etherbind(Ipifc *ifc, int argc, char **argv) */ snprint(addr, sizeof(addr), "%s/stats", dir); buf = smalloc(512); - achan = namec(addr, Aopen, OREAD, 0); - n = devtab[achan->type]->read(achan, buf, 511, 0); - cclose(achan); + schan = namec(addr, Aopen, OREAD, 0); + if(waserror()){ + cclose(schan); + nexterror(); + } + n = devtab[schan->type]->read(schan, buf, 511, 0); + cclose(schan); + poperror(); buf[n] = 0; ptr = strstr(buf, "addr: "); diff --git a/ip/tcp.c b/ip/tcp.c index 9f8433700e2b10bc7739bc3dcfea839543d8ad53..6d9c4d059cc35255eb52b83d2e338c8d9a04feab 100644 --- a/ip/tcp.c +++ b/ip/tcp.c @@ -679,23 +679,19 @@ tcpmtu(Conv *s) uchar version; version = s->ipversion; - mtu = 0; ifc = findipifc(s->p->f, s->raddr, 0); - if(ifc != nil) { - switch(version){ - case V4: + switch(version){ + default: + case V4: + mtu = DEF_MSS; + if(ifc != nil) mtu = ifc->maxmtu - ifc->m->hsize - (TCP4_PKT + TCP4_HDRSIZE); - break; - case V6: + break; + case V6: + mtu = DEF_MSS6; + if(ifc != nil) mtu = ifc->maxmtu - ifc->m->hsize - (TCP6_PKT + TCP6_HDRSIZE); - break; - default: - panic("tcpmtu: version %d", version); - } - } - - if(mtu < 32) { - mtu = 1280; + break; } return mtu; @@ -1665,6 +1661,19 @@ reset: break; } + if(tcb->state != Syn_received){ + /* + * One DOS attack is to open connections to us and then forget about them, + * thereby tying up a conv at no long term cost to the attacker. + * This is an attempt to defeat these stateless DOS attacks. See + * corresponding code in tcpsendka(). + */ + if(seq_within(seg.ack, tcb->snd.una-(1<<31), tcb->snd.una-(1<<29))){ + print("stateless hog %lux - %lux - %lux\n", tcb->snd.una-(1<<31), seg.ack, tcb->snd.una-(1<<29)); + localclose(s, "stateless hog"); + } + } + /* Cut the data to fit the receive window */ if(tcptrim(tcb, &seg, &bp, &length) == -1) { netlog(f, Logtcp, "tcp len < 0, %lux\n", seg.seq); @@ -2122,6 +2131,10 @@ tcpoutput(Conv *s) /* * the BSD convention (hack?) for keep alives. resend last uchar acked. + * + * To avoid stateless Conv hogs, we pick a sequence number at random. If + * it that number gets acked by the other end, we shut down the connection. + * See the equivalent code in tcpiput(). */ void tcpsendka(Conv *s) @@ -2138,7 +2151,7 @@ tcpsendka(Conv *s) seg.dest = s->rport; seg.flags = ACK|PSH; seg.mss = 0; - seg.seq = tcb->snd.una-1; + seg.seq = tcb->snd.una-(1<<30)-nrand(1<<20); seg.ack = tcb->rcv.nxt; seg.wnd = tcb->rcv.wnd; tcb->last_ack = tcb->rcv.nxt; @@ -2320,7 +2333,6 @@ void procsyn(Conv *s, Tcp *seg) { Tcpctl *tcb; - int mtu; tcb = (Tcpctl*)s->ptcl; tcb->flags |= FORCE; @@ -2330,14 +2342,9 @@ procsyn(Conv *s, Tcp *seg) tcb->irs = seg->seq; tcb->snd.wnd = seg->wnd; - if(seg->mss != 0) + if(seg->mss != 0 && seg->mss < tcb->mss) tcb->mss = seg->mss; - tcb->max_snd = seg->wnd; - - mtu = tcpmtu(s); - if(tcb->mss > mtu) - tcb->mss = mtu; tcb->cwind = tcb->mss; } diff --git a/port/devrealtime.c b/port/devrealtime.c index f52508001677b2c20c0f73682de70c814ba16a7d..249406889729e05f6baf7dcfb5a8d9d94596e784 100644 --- a/port/devrealtime.c +++ b/port/devrealtime.c @@ -13,6 +13,7 @@ /* debugging */ extern int edfprint; +extern Edfinterface realedf, *edf; static Schedevent *events; static int nevents, revent, wevent; @@ -219,6 +220,7 @@ devrtinit(void) events = (Schedevent *)malloc(sizeof(Schedevent) * Nevents); assert(events); nevents = revent = wevent = 0; + edf = &realedf; } static Chan * @@ -286,7 +288,7 @@ devrtopen(Chan *c, int mode) case Qclone: if (mode == OREAD) error(Eperm); - edfinit(); + edf->edfinit(); /* open a new task */ for (t = tasks; t< tasks + Maxtasks; t++){ qlock(t); @@ -638,7 +640,7 @@ removetask(Task *t) Resource *r; qlock(t); - edfexpel(t); + edf->edfexpel(t); for (pp = t->procs; pp < t->procs + nelem(t->procs); pp++) if (p = *pp) p->task = nil; @@ -724,7 +726,7 @@ devrtwrite(Chan *c, void *va, long n, vlong) if (e=parsetime(&time, v)) error(e); ticks = time2ticks(time); - edfexpel(t); + edf->edfexpel(t); switch(add){ case -1: if (ticks > t->T) @@ -745,7 +747,7 @@ devrtwrite(Chan *c, void *va, long n, vlong) if (e=parsetime(&time, v)) error(e); ticks = time2ticks(time); - edfexpel(t); + edf->edfexpel(t); switch(add){ case -1: if (ticks > t->D) @@ -764,7 +766,7 @@ devrtwrite(Chan *c, void *va, long n, vlong) if (e=parsetime(&time, v)) error(e); ticks = time2ticks(time); - edfexpel(t); + edf->edfexpel(t); switch(add){ case -1: if (ticks > t->C) @@ -784,7 +786,7 @@ devrtwrite(Chan *c, void *va, long n, vlong) }else if (strcmp(a, "resources") == 0){ if (v == nil) error("resources: value missing"); - edfexpel(t); + edf->edfexpel(t); if (add == 0){ for (rp = t->res; rp < t->res + nelem(t->res); rp++) if (*rp){ @@ -809,7 +811,7 @@ devrtwrite(Chan *c, void *va, long n, vlong) if (v == nil) error("procs: value missing"); if (add <= 0){ - edfexpel(t); + edf->edfexpel(t); } if (add == 0){ for (pp = t->procs; pp < t->procs + nelem(t->procs); pp++) @@ -835,10 +837,10 @@ devrtwrite(Chan *c, void *va, long n, vlong) error(e); } }else if (strcmp(a, "admit") == 0){ - if (e = edfadmit(t)) + if (e = edf->edfadmit(t)) error(e); }else if (strcmp(a, "expel") == 0){ - edfexpel(t); + edf->edfexpel(t); }else if (strcmp(a, "remove") == 0){ removetask(t); return n; /* Ignore any subsequent commands */ @@ -857,8 +859,8 @@ devrtwrite(Chan *c, void *va, long n, vlong) else t->flags |= Useblocking; }else if (strcmp(a, "yield") == 0){ - if (isedf(up) && up->task == t){ - edfdeadline(up); /* schedule next release */ + if (edf->isedf(up) && up->task == t){ + edf->edfdeadline(up); /* schedule next release */ sched(); }else error("yield outside task"); diff --git a/port/edf.c b/port/edf.c index 0b1263c32cf9569458bf060200b40a61bd5e444d..d0d6d1c5d794dd6e2486eddf2a3bacb827e10786 100644 --- a/port/edf.c +++ b/port/edf.c @@ -49,6 +49,7 @@ enum{ static int earlierrelease(Task *t1, Task *t2) {return t1->r < t2->r;} static int earlierdeadline(Task *t1, Task *t2) {return t1->d < t2->d;} +static void edfrelease(Task *t); /* Tasks waiting for release, head earliest release time */ Taskq qwaitrelease = {{0}, nil, earlierrelease}; @@ -71,7 +72,7 @@ static void edfreleaseintr(Ureg *, Timer *cy); static void edfdeadlineintr(Ureg*, Timer*); static char * edftestschedulability(Task *thetask); -void +static void edfinit(void) { int i; @@ -96,13 +97,13 @@ edfinit(void) iunlock(&edflock); } -int +static int isedf(Proc *p) { return p && p->task && p->task->state >= EdfIdle; } -int +static int edfanyready(void) { return edfstack[m->machno].head || qreleased.head; @@ -220,7 +221,7 @@ edfreleasetimer(void) timeradd(&releasetimer[m->machno]); } -void +static void edfblock(Proc *p) { Task *t, *pt; @@ -284,7 +285,7 @@ deadline(Proc *p, SEvent why) edfresched(t); } -void +static void edfdeadline(Proc *p) { DPRINT("%d edfdeadline\n", m->machno); @@ -295,7 +296,7 @@ edfdeadline(Proc *p) iunlock(&edflock); } -char * +static char * edfadmit(Task *t) { char *err; @@ -361,7 +362,7 @@ edfadmit(Task *t) return nil; } -void +static void edfexpel(Task *t) { Task *tt; @@ -492,7 +493,7 @@ edfdeadlineintr(Ureg*, Timer*) splhi(); } -void +static void edfbury(Proc *p) { Task *t; @@ -526,7 +527,7 @@ edfbury(Proc *p) iunlock(&edflock); } -void +static void edfready(Proc *p) { Task *t; @@ -671,7 +672,7 @@ edfresched(Task *t) } } -void +static void edfrelease(Task *t) { DPRINT("%d edfrelease, %s, %d\n", m->machno, edfstatename[t->state], t->runq.n); @@ -685,7 +686,7 @@ edfrelease(Task *t) if(devrt) devrt(t, now, SRelease); } -Proc * +static Proc * edfrunproc(void) { /* Return an edf proc to run or nil */ @@ -961,3 +962,16 @@ time2ticks(Time time) assert(time >= 0); return uvmuldiv(time, fasthz, Onesecond); } + +Edfinterface realedf = { + .isedf = isedf, + .edfbury = edfbury, + .edfanyready = edfanyready, + .edfready = edfready, + .edfrunproc = edfrunproc, + .edfblock = edfblock, + .edfinit = edfinit, + .edfexpel = edfexpel, + .edfadmit = edfadmit, + .edfdeadline = edfdeadline, +}; diff --git a/port/edf.h b/port/edf.h index a8e1f399b5e7369d87783e9eb697b48e0fd7203f..03ba40b4670d8a38005927426b33998107a8061f 100644 --- a/port/edf.h +++ b/port/edf.h @@ -14,10 +14,10 @@ enum { typedef vlong Time; typedef uvlong Ticks; -typedef struct Task Task; -typedef struct Resource Resource; -typedef struct Edf Edf; -typedef struct Taskq Taskq; +typedef struct Task Task; +typedef struct Resource Resource; +typedef struct Edf Edf; +typedef struct Taskq Taskq; enum Edfstate { EdfUnused, /* task structure not in use */ diff --git a/port/nulledf.c b/port/nulledf.c index 7ab36fc3152edbe2a5c3d1812f5934b3578b84ed..db630b20ee238e3a5dd7e43cb8d27a4c1c17021a 100644 --- a/port/nulledf.c +++ b/port/nulledf.c @@ -6,36 +6,69 @@ #include "../port/error.h" #include "../port/edf.h" -int +static int isedf(Proc*) { return 0; } -void +static void edfbury(Proc*) { } -int +static int edfanyready(void) { return 0; } -void +static void edfready(Proc*) { } -Proc* +static Proc* edfrunproc(void) { return nil; } -void +static void edfblock(Proc*) { } +static void +edfinit(void) +{ +} + +static void +edfexpel(Task*) +{ +} + +static char * +edfadmit(Task*) +{ + return "No edf"; +} + +static void +edfdeadline(Proc*) +{ +} + +Edfinterface nulledf = { + .isedf = isedf, + .edfbury = edfbury, + .edfanyready = edfanyready, + .edfready = edfready, + .edfrunproc = edfrunproc, + .edfblock = edfblock, + .edfinit = edfinit, + .edfexpel = edfexpel, + .edfadmit = edfadmit, + .edfdeadline = edfdeadline, +}; diff --git a/port/portclock.c b/port/portclock.c index 04761203c0c95772369e8ba907436a9ba74028a7..fec208181cafc2fee3374d30efe537ff4a8176fe 100644 --- a/port/portclock.c +++ b/port/portclock.c @@ -122,7 +122,7 @@ hzclock(Ureg *ur) return; /* i.e. don't deschedule an EDF process here! */ - if(anyready() && !isedf(up)){ + if(anyready() && !edf->isedf(up)){ sched(); splhi(); } diff --git a/port/portdat.h b/port/portdat.h index 619cf34f7feca8d4e958463308038a0d4622b7d2..8da75534ea090205dc409c778f9d413e3b3dd288 100644 --- a/port/portdat.h +++ b/port/portdat.h @@ -6,6 +6,7 @@ typedef struct Cmdtab Cmdtab; typedef struct Cname Cname; typedef struct Dev Dev; typedef struct Dirtab Dirtab; +typedef struct Edfinterface Edfinterface; typedef struct Egrp Egrp; typedef struct Evalue Evalue; typedef struct Fgrp Fgrp; @@ -846,6 +847,21 @@ struct Timer ulong period; }; +struct Edfinterface { + int (*isedf)(Proc*); + void (*edfbury)(Proc*); + int (*edfanyready)(void); + void (*edfready)(Proc*); + Proc* (*edfrunproc)(void); + void (*edfblock)(Proc*); + void (*edfinit)(void); + void (*edfexpel)(Task *t); + char * (*edfadmit)(Task *t); + void (*edfdeadline)(Proc *p); +}; + +extern Edfinterface *edf; + #define DEVDOTDOT -1 #pragma varargck argpos print 1 diff --git a/port/portfns.h b/port/portfns.h index b0cd038bbf254915dfd6fc01f1877d996764fd85..ee8b9bd19a6a4520500d81cebc67a19139b8c9ba 100644 --- a/port/portfns.h +++ b/port/portfns.h @@ -87,17 +87,6 @@ void dumpstack(void); Fgrp* dupfgrp(Fgrp*); void duppage(Page*); void dupswap(Page*); -void edfdeadline(Proc*); -void edfrelease(Task*); -char* edfadmit(Task*); -void edfexpel(Task*); -void edfbury(Proc*); -void edfsched(Task*); -int edfanyready(void); -void edfready(Proc*); -Proc* edfrunproc(void); -void edfblock(Proc*); -void edfinit(void); int emptystr(char*); int encrypt(void*, void*, int); void envcpy(Egrp*, Egrp*); @@ -140,7 +129,6 @@ int incref(Ref*); void initseg(void); int iprint(char*, ...); void isdir(Chan*); -int isedf(Proc*); int iseve(void); int islo(void); Segment* isoverlap(Proc*, ulong, int); diff --git a/port/proc.c b/port/proc.c index 6844083d743276930a7ef0efd84d26049e7fc481..6d3d727dda84a35696e292702f6bfebcf21661f1 100644 --- a/port/proc.c +++ b/port/proc.c @@ -22,6 +22,10 @@ static struct Procalloc static Schedq runq[Nrq]; +extern Edfinterface nulledf; + +Edfinterface *edf = &nulledf; + char *statename[] = { /* BUG: generate automatically */ "Dead", @@ -57,8 +61,8 @@ schedinit(void) /* never returns */ break; case Moribund: up->state = Dead; - if (isedf(up)) - edfbury(up); + if (edf->isedf(up)) + edf->edfbury(up); /* * Holding locks from pexit: @@ -122,7 +126,7 @@ sched(void) int anyready(void) { - return nrdy || edfanyready(); + return nrdy || edf->edfanyready(); } int @@ -153,8 +157,8 @@ ready(Proc *p) s = splhi(); - if(isedf(p)){ - edfready(p); + if(edf->isedf(p)){ + edf->edfready(p); splx(s); return; } @@ -208,7 +212,7 @@ runproc(void) Proc *p, *l; ulong rt; - if ((p = edfrunproc()) != nil) + if ((p = edf->edfrunproc()) != nil) return p; loop: @@ -503,8 +507,8 @@ sleep(Rendez *r, int (*f)(void*), void *arg) unlock(r); // Behind unlock, we may call wakeup on ourselves. - if (isedf(up)) - edfblock(up); + if (edf->isedf(up)) + edf->edfblock(up); gotolabel(&m->sched); } @@ -713,8 +717,8 @@ addbroken(Proc *p) broken.p[broken.n++] = p; qunlock(&broken); - if (isedf(up)) - edfbury(up); + if (edf->isedf(up)) + edf->edfbury(up); p->state = Broken; p->psstate = 0; sched(); @@ -884,8 +888,8 @@ pexit(char *exitstr, int freemem) lock(&procalloc); lock(&palloc); - if (isedf(up)) - edfbury(up); + if (edf->isedf(up)) + edf->edfbury(up); up->state = Moribund; sched(); panic("pexit"); @@ -1139,8 +1143,8 @@ procctl(Proc *p) qunlock(&p->debug); splhi(); p->state = Stopped; - if (isedf(up)) - edfblock(up); + if (edf->isedf(up)) + edf->edfblock(up); sched(); p->psstate = state; splx(s); diff --git a/port/qlock.c b/port/qlock.c index 629fcd4d6b5a7dedb9427d5c8843dc6dd909a476..0f14c41e71055fcd2fe385beeace44b50d9cb82c 100644 --- a/port/qlock.c +++ b/port/qlock.c @@ -43,8 +43,8 @@ qlock(QLock *q) up->state = Queueing; up->qpc = getcallerpc(&q); unlock(&q->use); - if(isedf(up)) - edfblock(up); + if(edf->isedf(up)) + edf->edfblock(up); sched(); } @@ -107,8 +107,8 @@ rlock(RWlock *q) up->qnext = 0; up->state = QueueingR; unlock(&q->use); - if (isedf(up)) - edfblock(up); + if (edf->isedf(up)) + edf->edfblock(up); sched(); } @@ -164,8 +164,8 @@ wlock(RWlock *q) up->qnext = 0; up->state = QueueingW; unlock(&q->use); - if (isedf(up)) - edfblock(up); + if (edf->isedf(up)) + edf->edfblock(up); sched(); } diff --git a/port/sysproc.c b/port/sysproc.c index 73d10bed3d0e14c587a2402debca7ec6f1f5a4cb..c23d205790aa7e547b9cd81db81a0b5887efc50c 100644 --- a/port/sysproc.c +++ b/port/sysproc.c @@ -839,8 +839,8 @@ sysrendezvous(ulong *arg) *l = up; up->state = Rendezvous; unlock(up->rgrp); - if (isedf(up)) - edfblock(up); + if (edf->isedf(up)) + edf->edfblock(up); sched();