diff options
author | andre <andre@FreeBSD.org> | 2004-10-23 18:52:06 +0000 |
---|---|---|
committer | andre <andre@FreeBSD.org> | 2004-10-23 18:52:06 +0000 |
commit | 1422b332e118bc73743bd81103aac4fd8b5e4636 (patch) | |
tree | 1678a301b0b6d9131523b2e3202df9b71fe891f9 /sys/kern/uipc_domain.c | |
parent | 145b9af82cdfb6e69476541a8826a72b41146606 (diff) | |
download | FreeBSD-src-1422b332e118bc73743bd81103aac4fd8b5e4636.zip FreeBSD-src-1422b332e118bc73743bd81103aac4fd8b5e4636.tar.gz |
Aquire GIANT in pf_proto_[un]register() before manipulating the protosw.
Diffstat (limited to 'sys/kern/uipc_domain.c')
-rw-r--r-- | sys/kern/uipc_domain.c | 32 |
1 files changed, 27 insertions, 5 deletions
diff --git a/sys/kern/uipc_domain.c b/sys/kern/uipc_domain.c index c9fe395..2ce5080 100644 --- a/sys/kern/uipc_domain.c +++ b/sys/kern/uipc_domain.c @@ -237,23 +237,36 @@ found: npr->pr_domain = dp; fpr = NULL; + /* + * Protect us against races when two protocol registrations for + * the same protocol happen at the same time. + */ + mtx_lock(&Giant); + /* The new protocol must not yet exist. */ for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) { if ((pr->pr_type == npr->pr_type) && - (pr->pr_protocol == npr->pr_protocol)) + (pr->pr_protocol == npr->pr_protocol)) { + mtx_unlock(&Giant); return (EEXIST); /* XXX: Check only protocol? */ + } /* While here, remember the first free spacer. */ if ((fpr == NULL) && (pr->pr_protocol == PROTO_SPACER)) fpr = pr; } /* If no free spacer is found we can't add the new protocol. */ - if (fpr == NULL) + if (fpr == NULL) { + mtx_unlock(&Giant); return (ENOMEM); + } /* Copy the new struct protosw over the spacer. */ bcopy(npr, fpr, sizeof(*fpr)); + /* Job is done, no more protection required. */ + mtx_unlock(&Giant); + /* Initialize and activate the protocol. */ if (fpr->pr_init) (fpr->pr_init)(); @@ -291,19 +304,25 @@ pf_proto_unregister(family, protocol, type) found: dpr = NULL; + /* Lock out everyone else while we are manipulating the protosw. */ + mtx_lock(&Giant); + /* The protocol must exist and only once. */ for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) { if ((pr->pr_type == type) && (pr->pr_protocol == protocol)) { - if (dpr != NULL) + if (dpr != NULL) { + mtx_unlock(&Giant); return (EMLINK); /* Should not happen! */ - else + } else dpr = pr; } } /* Protocol does not exist. */ - if (dpr == NULL) + if (dpr == NULL) { + mtx_unlock(&Giant); return (EPROTONOSUPPORT); + } /* De-orbit the protocol and make the slot available again. */ dpr->pr_type = 0; @@ -321,6 +340,9 @@ found: dpr->pr_drain = NULL; dpr->pr_usrreqs = &nousrreqs; + /* Job is done, not more protection required. */ + mtx_unlock(&Giant); + return (0); } |