From 6bde73b3427d0e5dd4872ea37c4ffd03143181a6 Mon Sep 17 00:00:00 2001 From: simon Date: Wed, 6 Jan 2010 21:45:30 +0000 Subject: [PATCH] Fix BIND named(8) cache poisoning with DNSSEC validation. [SA-10:01] Fix ntpd mode 7 denial of service. [SA-10:02] Fix ZFS ZIL playback with insecure permissions. [SA-10:03] Various FreeBSD 8.0-RELEASE improvements. [EN-10:01] Security: FreeBSD-SA-10:01.bind Security: FreeBSD-SA-10:02.ntpd Security: FreeBSD-SA-10:03.zfs Errata: FreeBSD-EN-10:01.freebsd Approved by: so (simon) git-svn-id: svn://svn.freebsd.org/base/releng/8.0@201679 ccf9f872-aa2e-dd11-9fc8-001c23d0bc1f --- UPDATING | 11 ++++ contrib/bind9/bin/named/query.c | 66 +++++++++++++++---- contrib/bind9/lib/dns/include/dns/types.h | 32 ++++++--- contrib/bind9/lib/dns/masterdump.c | 3 +- contrib/bind9/lib/dns/rbtdb.c | 4 +- contrib/bind9/lib/dns/resolver.c | 31 +++++++-- contrib/bind9/lib/dns/validator.c | 10 +-- contrib/ntp/ntpd/ntp_request.c | 11 +++- sys/cddl/compat/opensolaris/sys/vnode.h | 2 + .../uts/common/fs/zfs/zfs_replay.c | 12 ++-- .../opensolaris/uts/common/fs/zfs/zfs_vnops.c | 30 ++++++--- .../opensolaris/uts/common/fs/zfs/zfs_znode.c | 39 +++++------ .../opensolaris/uts/common/sys/vnode.h | 1 - sys/conf/newvers.sh | 2 +- sys/kern/vfs_lookup.c | 6 ++ sys/netinet/ip_mroute.c | 9 +++ sys/netinet/raw_ip.c | 34 +++++++--- sys/netinet/sctp_input.c | 3 + sys/netinet6/raw_ip6.c | 38 ++++++++--- sys/rpc/clnt_vc.c | 16 +++++ 20 files changed, 273 insertions(+), 87 deletions(-) diff --git a/UPDATING b/UPDATING index a1089fa9..a2a59f22 100644 --- a/UPDATING +++ b/UPDATING @@ -15,6 +15,17 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 8.x IS SLOW ON IA64 OR SUN4V: debugging tools present in HEAD were left in place because sun4v support still needs work to become production ready. +20100106: p2 FreeBSD-SA-10:01.bind, FreeBSD-SA-10:02.ntpd, + FreeBSD-SA-10:03.zfs, FreeBSD-EN-10:01.freebsd + Fix BIND named(8) cache poisoning with DNSSEC validation. + [SA-10:01] + + Fix ntpd mode 7 denial of service. [SA-10:02] + + Fix ZFS ZIL playback with insecure permissions. [SA-10:03] + + Various FreeBSD 8.0-RELEASE improvements. [EN-10:01] + 20091203: p1 FreeBSD-SA-09:15.ssl, FreeBSD-SA-09:16.rtld, FreeBSD-SA-09:17.freebsd-update Disable SSL renegotiation in order to protect against a serious diff --git a/contrib/bind9/bin/named/query.c b/contrib/bind9/bin/named/query.c index ffd9b355..3f13347e 100644 --- a/contrib/bind9/bin/named/query.c +++ b/contrib/bind9/bin/named/query.c @@ -116,6 +116,8 @@ #define DNS_GETDB_NOLOG 0x02U #define DNS_GETDB_PARTIAL 0x04U +#define PENDINGOK(x) (((x) & DNS_DBFIND_PENDINGOK) != 0) + typedef struct client_additionalctx { ns_client_t *client; dns_rdataset_t *rdataset; @@ -1761,8 +1763,8 @@ query_addadditional2(void *arg, dns_name_t *name, dns_rdatatype_t qtype) { */ if (result == ISC_R_SUCCESS && additionaltype == dns_rdatasetadditional_fromcache && - (rdataset->trust == dns_trust_pending || - rdataset->trust == dns_trust_glue) && + (DNS_TRUST_PENDING(rdataset->trust) || + DNS_TRUST_GLUE(rdataset->trust)) && !validate(client, db, fname, rdataset, sigrdataset)) { dns_rdataset_disassociate(rdataset); if (dns_rdataset_isassociated(sigrdataset)) @@ -1801,8 +1803,8 @@ query_addadditional2(void *arg, dns_name_t *name, dns_rdatatype_t qtype) { */ if (result == ISC_R_SUCCESS && additionaltype == dns_rdatasetadditional_fromcache && - (rdataset->trust == dns_trust_pending || - rdataset->trust == dns_trust_glue) && + (DNS_TRUST_PENDING(rdataset->trust) || + DNS_TRUST_GLUE(rdataset->trust)) && !validate(client, db, fname, rdataset, sigrdataset)) { dns_rdataset_disassociate(rdataset); if (dns_rdataset_isassociated(sigrdataset)) @@ -2601,14 +2603,14 @@ query_addbestns(ns_client_t *client) { /* * Attempt to validate RRsets that are pending or that are glue. */ - if ((rdataset->trust == dns_trust_pending || - (sigrdataset != NULL && sigrdataset->trust == dns_trust_pending)) + if ((DNS_TRUST_PENDING(rdataset->trust) || + (sigrdataset != NULL && DNS_TRUST_PENDING(sigrdataset->trust))) && !validate(client, db, fname, rdataset, sigrdataset) && - (client->query.dboptions & DNS_DBFIND_PENDINGOK) == 0) + !PENDINGOK(client->query.dboptions)) goto cleanup; - if ((rdataset->trust == dns_trust_glue || - (sigrdataset != NULL && sigrdataset->trust == dns_trust_glue)) && + if ((DNS_TRUST_GLUE(rdataset->trust) || + (sigrdataset != NULL && DNS_TRUST_GLUE(sigrdataset->trust))) && !validate(client, db, fname, rdataset, sigrdataset) && SECURE(client) && WANTDNSSEC(client)) goto cleanup; @@ -3716,6 +3718,8 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) dns_rdataset_t *noqname; isc_boolean_t resuming; int line = -1; + dns_rdataset_t tmprdataset; + unsigned int dboptions; CTRACE("query_find"); @@ -3933,9 +3937,49 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) /* * Now look for an answer in the database. */ + dboptions = client->query.dboptions; + if (sigrdataset == NULL && client->view->enablednssec) { + /* + * If the client doesn't want DNSSEC we still want to + * look for any data pending validation to save a remote + * lookup if possible. + */ + dns_rdataset_init(&tmprdataset); + sigrdataset = &tmprdataset; + dboptions |= DNS_DBFIND_PENDINGOK; + } + refind: result = dns_db_find(db, client->query.qname, version, type, - client->query.dboptions, client->now, - &node, fname, rdataset, sigrdataset); + dboptions, client->now, &node, fname, + rdataset, sigrdataset); + /* + * If we have found pending data try to validate it. + * If the data does not validate as secure and we can't + * use the unvalidated data requery the database with + * pending disabled to prevent infinite looping. + */ + if (result != ISC_R_SUCCESS || !DNS_TRUST_PENDING(rdataset->trust)) + goto validation_done; + if (validate(client, db, fname, rdataset, sigrdataset)) + goto validation_done; + if (rdataset->trust != dns_trust_pending_answer || + !PENDINGOK(client->query.dboptions)) { + dns_rdataset_disassociate(rdataset); + if (sigrdataset != NULL && + dns_rdataset_isassociated(sigrdataset)) + dns_rdataset_disassociate(sigrdataset); + if (sigrdataset == &tmprdataset) + sigrdataset = NULL; + dns_db_detachnode(db, &node); + dboptions &= ~DNS_DBFIND_PENDINGOK; + goto refind; + } + validation_done: + if (sigrdataset == &tmprdataset) { + if (dns_rdataset_isassociated(sigrdataset)) + dns_rdataset_disassociate(sigrdataset); + sigrdataset = NULL; + } resume: CTRACE("query_find: resume"); diff --git a/contrib/bind9/lib/dns/include/dns/types.h b/contrib/bind9/lib/dns/include/dns/types.h index e07a7965..73a6e322 100644 --- a/contrib/bind9/lib/dns/include/dns/types.h +++ b/contrib/bind9/lib/dns/include/dns/types.h @@ -258,40 +258,52 @@ enum { dns_trust_none = 0, #define dns_trust_none ((dns_trust_t)dns_trust_none) - /*% Subject to DNSSEC validation but has not yet been validated */ - dns_trust_pending = 1, -#define dns_trust_pending ((dns_trust_t)dns_trust_pending) + /*% + * Subject to DNSSEC validation but has not yet been validated + * dns_trust_pending_additional (from the additional section). + */ + dns_trust_pending_additional = 1, +#define dns_trust_pending_additional \ + ((dns_trust_t)dns_trust_pending_additional) + + dns_trust_pending_answer = 2, +#define dns_trust_pending_answer ((dns_trust_t)dns_trust_pending_answer) /*% Received in the additional section of a response. */ - dns_trust_additional = 2, + dns_trust_additional = 3, #define dns_trust_additional ((dns_trust_t)dns_trust_additional) /* Received in a referral response. */ - dns_trust_glue = 3, + dns_trust_glue = 4, #define dns_trust_glue ((dns_trust_t)dns_trust_glue) /* Answer from a non-authoritative server */ - dns_trust_answer = 4, + dns_trust_answer = 5, #define dns_trust_answer ((dns_trust_t)dns_trust_answer) /* Received in the authority section as part of an authoritative response */ - dns_trust_authauthority = 5, + dns_trust_authauthority = 6, #define dns_trust_authauthority ((dns_trust_t)dns_trust_authauthority) /* Answer from an authoritative server */ - dns_trust_authanswer = 6, + dns_trust_authanswer = 7, #define dns_trust_authanswer ((dns_trust_t)dns_trust_authanswer) /* Successfully DNSSEC validated */ - dns_trust_secure = 7, + dns_trust_secure = 8, #define dns_trust_secure ((dns_trust_t)dns_trust_secure) /* This server is authoritative */ - dns_trust_ultimate = 8 + dns_trust_ultimate = 9 #define dns_trust_ultimate ((dns_trust_t)dns_trust_ultimate) }; +#define DNS_TRUST_PENDING(x) ((x) == dns_trust_pending_answer || \ + (x) == dns_trust_pending_additional) +#define DNS_TRUST_GLUE(x) ((x) == dns_trust_glue) + + /*% * Name checking severities. */ diff --git a/contrib/bind9/lib/dns/masterdump.c b/contrib/bind9/lib/dns/masterdump.c index 5eac96ff..84f3d276 100644 --- a/contrib/bind9/lib/dns/masterdump.c +++ b/contrib/bind9/lib/dns/masterdump.c @@ -775,7 +775,8 @@ dump_order_compare(const void *a, const void *b) { static const char *trustnames[] = { "none", - "pending", + "pending-additional", + "pending-answer", "additional", "glue", "answer", diff --git a/contrib/bind9/lib/dns/rbtdb.c b/contrib/bind9/lib/dns/rbtdb.c index 9741c157..201fc391 100644 --- a/contrib/bind9/lib/dns/rbtdb.c +++ b/contrib/bind9/lib/dns/rbtdb.c @@ -4005,7 +4005,7 @@ cache_zonecut_callback(dns_rbtnode_t *node, dns_name_t *name, void *arg) { } if (dname_header != NULL && - (dname_header->trust != dns_trust_pending || + (!DNS_TRUST_PENDING(dname_header->trust) || (search->options & DNS_DBFIND_PENDINGOK) != 0)) { /* * We increment the reference count on node to ensure that @@ -4548,7 +4548,7 @@ cache_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version, if (found == NULL || (found->trust == dns_trust_glue && ((options & DNS_DBFIND_GLUEOK) == 0)) || - (found->trust == dns_trust_pending && + (DNS_TRUST_PENDING(found->trust) && ((options & DNS_DBFIND_PENDINGOK) == 0))) { /* * If there is an NS rdataset at this node, then this is the diff --git a/contrib/bind9/lib/dns/resolver.c b/contrib/bind9/lib/dns/resolver.c index a5d7c250..0d513b29 100644 --- a/contrib/bind9/lib/dns/resolver.c +++ b/contrib/bind9/lib/dns/resolver.c @@ -4293,6 +4293,7 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_adbaddrinfo_t *addrinfo, * for it, unless it is glue. */ if (secure_domain && rdataset->trust != dns_trust_glue) { + dns_trust_t trust; /* * RRSIGs are validated as part of validating the * type they cover. @@ -4329,12 +4330,34 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_adbaddrinfo_t *addrinfo, } /* + * Reject out of bailiwick additional records + * without RRSIGs as they can't possibly validate + * as "secure" and as we will never never want to + * store these as "answers" after validation. + */ + if (rdataset->trust == dns_trust_additional && + sigrdataset == NULL && EXTERNAL(rdataset)) + continue; + + /* + * XXXMPA: If we store as "answer" after validating + * then we need to do bailiwick processing and + * also need to track whether RRsets are in or + * out of bailiwick. This will require a another + * pending trust level. + * * Cache this rdataset/sigrdataset pair as - * pending data. + * pending data. Track whether it was additional + * or not. */ - rdataset->trust = dns_trust_pending; + if (rdataset->trust == dns_trust_additional) + trust = dns_trust_pending_additional; + else + trust = dns_trust_pending_answer; + + rdataset->trust = trust; if (sigrdataset != NULL) - sigrdataset->trust = dns_trust_pending; + sigrdataset->trust = trust; if (!need_validation || !ANSWER(rdataset)) { addedrdataset = ardataset; result = dns_db_addrdataset(fctx->cache, node, @@ -4682,7 +4705,7 @@ ncache_message(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, for (trdataset = ISC_LIST_HEAD(tname->list); trdataset != NULL; trdataset = ISC_LIST_NEXT(trdataset, link)) - trdataset->trust = dns_trust_pending; + trdataset->trust = dns_trust_pending_answer; result = dns_message_nextname(fctx->rmessage, DNS_SECTION_AUTHORITY); } diff --git a/contrib/bind9/lib/dns/validator.c b/contrib/bind9/lib/dns/validator.c index c62b7141..a6f8302b 100644 --- a/contrib/bind9/lib/dns/validator.c +++ b/contrib/bind9/lib/dns/validator.c @@ -1607,7 +1607,7 @@ get_key(dns_validator_t *val, dns_rdata_rrsig_t *siginfo) { * We have an rrset for the given keyname. */ val->keyset = &val->frdataset; - if (val->frdataset.trust == dns_trust_pending && + if (DNS_TRUST_PENDING(val->frdataset.trust) && dns_rdataset_isassociated(&val->fsigrdataset)) { /* @@ -1622,7 +1622,7 @@ get_key(dns_validator_t *val, dns_rdata_rrsig_t *siginfo) { if (result != ISC_R_SUCCESS) return (result); return (DNS_R_WAIT); - } else if (val->frdataset.trust == dns_trust_pending) { + } else if (DNS_TRUST_PENDING(val->frdataset.trust)) { /* * Having a pending key with no signature means that * something is broken. @@ -2243,7 +2243,7 @@ validatezonekey(dns_validator_t *val) { * We have DS records. */ val->dsset = &val->frdataset; - if (val->frdataset.trust == dns_trust_pending && + if (DNS_TRUST_PENDING(val->frdataset.trust) && dns_rdataset_isassociated(&val->fsigrdataset)) { result = create_validator(val, @@ -2256,7 +2256,7 @@ validatezonekey(dns_validator_t *val) { if (result != ISC_R_SUCCESS) return (result); return (DNS_R_WAIT); - } else if (val->frdataset.trust == dns_trust_pending) { + } else if (DNS_TRUST_PENDING(val->frdataset.trust)) { /* * There should never be an unsigned DS. */ @@ -3337,7 +3337,7 @@ proveunsecure(dns_validator_t *val, isc_boolean_t have_ds, isc_boolean_t resume) * There is no DS. If this is a delegation, * we maybe done. */ - if (val->frdataset.trust == dns_trust_pending) { + if (DNS_TRUST_PENDING(val->frdataset.trust)) { result = create_fetch(val, tname, dns_rdatatype_ds, dsfetched2, diff --git a/contrib/ntp/ntpd/ntp_request.c b/contrib/ntp/ntpd/ntp_request.c index b1bc99d6..67bad2a8 100644 --- a/contrib/ntp/ntpd/ntp_request.c +++ b/contrib/ntp/ntpd/ntp_request.c @@ -409,6 +409,7 @@ process_private( int mod_okay ) { + static u_long quiet_until; struct req_pkt *inpkt; struct req_pkt_tail *tailinpkt; struct sockaddr_storage *srcadr; @@ -444,8 +445,14 @@ process_private( || (++ec, INFO_MBZ(inpkt->mbz_itemsize) != 0) || (++ec, rbufp->recv_length < REQ_LEN_HDR) ) { - msyslog(LOG_ERR, "process_private: INFO_ERR_FMT: test %d failed, pkt from %s", ec, stoa(srcadr)); - req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); + NLOG(NLOG_SYSEVENT) + if (current_time >= quiet_until) { + msyslog(LOG_ERR, + "process_private: drop test %d" + " failed, pkt from %s", + ec, stoa(srcadr)); + quiet_until = current_time + 60; + } return; } diff --git a/sys/cddl/compat/opensolaris/sys/vnode.h b/sys/cddl/compat/opensolaris/sys/vnode.h index 7611a3f8..7296635c 100644 --- a/sys/cddl/compat/opensolaris/sys/vnode.h +++ b/sys/cddl/compat/opensolaris/sys/vnode.h @@ -57,6 +57,8 @@ typedef struct vop_vector vnodeops_t; #define v_count v_usecount +#define V_APPEND VAPPEND + static __inline int vn_is_readonly(vnode_t *vp) { diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_replay.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_replay.c index 573a82c9..658e5399 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_replay.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_replay.c @@ -60,10 +60,14 @@ zfs_init_vattr(vattr_t *vap, uint64_t mask, uint64_t mode, { VATTR_NULL(vap); vap->va_mask = (uint_t)mask; - vap->va_type = IFTOVT(mode); - vap->va_mode = mode & MODEMASK; - vap->va_uid = (uid_t)(IS_EPHEMERAL(uid)) ? -1 : uid; - vap->va_gid = (gid_t)(IS_EPHEMERAL(gid)) ? -1 : gid; + if (mask & AT_TYPE) + vap->va_type = IFTOVT(mode); + if (mask & AT_MODE) + vap->va_mode = mode & MODEMASK; + if (mask & AT_UID) + vap->va_uid = (uid_t)(IS_EPHEMERAL(uid)) ? -1 : uid; + if (mask & AT_GID) + vap->va_gid = (gid_t)(IS_EPHEMERAL(gid)) ? -1 : gid; vap->va_rdev = zfs_cmpldev(rdev); vap->va_nodeid = nodeid; } diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c index a58f76e4..564871f6 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c @@ -3981,21 +3981,33 @@ zfs_freebsd_access(ap) struct thread *a_td; } */ *ap; { + accmode_t accmode; + int error = 0; /* - * ZFS itself only knowns about VREAD, VWRITE and VEXEC, the rest - * we have to handle by calling vaccess(). + * ZFS itself only knowns about VREAD, VWRITE, VEXEC and VAPPEND, */ - if ((ap->a_accmode & ~(VREAD|VWRITE|VEXEC)) != 0) { - vnode_t *vp = ap->a_vp; - znode_t *zp = VTOZ(vp); - znode_phys_t *zphys = zp->z_phys; + accmode = ap->a_accmode & (VREAD|VWRITE|VEXEC|VAPPEND); + if (accmode != 0) + error = zfs_access(ap->a_vp, accmode, 0, ap->a_cred, NULL); - return (vaccess(vp->v_type, zphys->zp_mode, zphys->zp_uid, - zphys->zp_gid, ap->a_accmode, ap->a_cred, NULL)); + /* + * VADMIN has to be handled by vaccess(). + */ + if (error == 0) { + accmode = ap->a_accmode & ~(VREAD|VWRITE|VEXEC|VAPPEND); + if (accmode != 0) { + vnode_t *vp = ap->a_vp; + znode_t *zp = VTOZ(vp); + znode_phys_t *zphys = zp->z_phys; + + error = vaccess(vp->v_type, zphys->zp_mode, + zphys->zp_uid, zphys->zp_gid, accmode, ap->a_cred, + NULL); + } } - return (zfs_access(ap->a_vp, ap->a_accmode, 0, ap->a_cred, NULL)); + return (error); } static int diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c index c43a8500..7157930f 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c @@ -143,16 +143,19 @@ zfs_znode_cache_constructor(void *buf, void *arg, int kmflags) POINTER_INVALIDATE(&zp->z_zfsvfs); ASSERT(!POINTER_IS_VALID(zp->z_zfsvfs)); - ASSERT(vfsp != NULL); - error = getnewvnode("zfs", vfsp, &zfs_vnodeops, &vp); - if (error != 0 && (kmflags & KM_NOSLEEP)) - return (-1); - ASSERT(error == 0); - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); - zp->z_vnode = vp; - vp->v_data = (caddr_t)zp; - VN_LOCK_AREC(vp); + if (vfsp != NULL) { + error = getnewvnode("zfs", vfsp, &zfs_vnodeops, &vp); + if (error != 0 && (kmflags & KM_NOSLEEP)) + return (-1); + ASSERT(error == 0); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); + zp->z_vnode = vp; + vp->v_data = (caddr_t)zp; + VN_LOCK_AREC(vp); + } else { + zp->z_vnode = NULL; + } list_link_init(&zp->z_link_node); @@ -1435,7 +1438,7 @@ zfs_create_fs(objset_t *os, cred_t *cr, nvlist_t *zplprops, dmu_tx_t *tx) nvpair_t *elem; int error; znode_t *rootzp = NULL; - vnode_t *vp; + vnode_t vnode; vattr_t vattr; znode_t *zp; @@ -1504,13 +1507,13 @@ zfs_create_fs(objset_t *os, cred_t *cr, nvlist_t *zplprops, dmu_tx_t *tx) vattr.va_gid = crgetgid(cr); rootzp = kmem_cache_alloc(znode_cache, KM_SLEEP); - zfs_znode_cache_constructor(rootzp, &zfsvfs, 0); + zfs_znode_cache_constructor(rootzp, NULL, 0); rootzp->z_unlinked = 0; rootzp->z_atime_dirty = 0; - vp = ZTOV(rootzp); - vp->v_type = VDIR; - VN_LOCK_ASHARE(vp); + vnode.v_type = VDIR; + vnode.v_data = rootzp; + rootzp->z_vnode = &vnode; bzero(&zfsvfs, sizeof (zfsvfs_t)); @@ -1539,16 +1542,10 @@ zfs_create_fs(objset_t *os, cred_t *cr, nvlist_t *zplprops, dmu_tx_t *tx) ASSERT(error == 0); POINTER_INVALIDATE(&rootzp->z_zfsvfs); - VI_LOCK(vp); - ZTOV(rootzp)->v_data = NULL; - ZTOV(rootzp)->v_count = 0; - ZTOV(rootzp)->v_holdcnt = 0; - rootzp->z_vnode = NULL; - VOP_UNLOCK(vp, 0); - vdestroy(vp); dmu_buf_rele(rootzp->z_dbuf, NULL); rootzp->z_dbuf = NULL; mutex_destroy(&zfsvfs.z_znodes_lock); + rootzp->z_vnode = NULL; kmem_cache_free(znode_cache, rootzp); } diff --git a/sys/cddl/contrib/opensolaris/uts/common/sys/vnode.h b/sys/cddl/contrib/opensolaris/uts/common/sys/vnode.h index a46b7118..5f1f4b45 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/sys/vnode.h +++ b/sys/cddl/contrib/opensolaris/uts/common/sys/vnode.h @@ -304,7 +304,6 @@ typedef struct xvattr { * VOP_ACCESS flags */ #define V_ACE_MASK 0x1 /* mask represents NFSv4 ACE permissions */ -#define V_APPEND 0x2 /* want to do append only check */ /* * Flags for vnode operations. diff --git a/sys/conf/newvers.sh b/sys/conf/newvers.sh index eae90b13..de53cd7f 100644 --- a/sys/conf/newvers.sh +++ b/sys/conf/newvers.sh @@ -32,7 +32,7 @@ TYPE="FreeBSD" REVISION="8.0" -BRANCH="RELEASE-p1" +BRANCH="RELEASE-p2" if [ "X${BRANCH_OVERRIDE}" != "X" ]; then BRANCH=${BRANCH_OVERRIDE} fi diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c index e553ae4d..51985622 100644 --- a/sys/kern/vfs_lookup.c +++ b/sys/kern/vfs_lookup.c @@ -552,6 +552,12 @@ dirloop: else cnp->cn_flags &= ~ISLASTCN; + if ((cnp->cn_flags & ISLASTCN) != 0 && + cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.' && + (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) { + error = EINVAL; + goto bad; + } /* * Check for degenerate name (e.g. / or "") diff --git a/sys/netinet/ip_mroute.c b/sys/netinet/ip_mroute.c index 39c71b06..48d5ffc0 100644 --- a/sys/netinet/ip_mroute.c +++ b/sys/netinet/ip_mroute.c @@ -1384,6 +1384,15 @@ fail: rt->mfc_rp.s_addr = INADDR_ANY; rt->mfc_bw_meter = NULL; + /* initialize pkt counters per src-grp */ + rt->mfc_pkt_cnt = 0; + rt->mfc_byte_cnt = 0; + rt->mfc_wrong_if = 0; + timevalclear(&rt->mfc_last_assert); + + TAILQ_INIT(&rt->mfc_stall); + rt->mfc_nstall = 0; + /* link into table */ LIST_INSERT_HEAD(&mfchashtbl[hash], rt, mfc_hash); TAILQ_INSERT_HEAD(&rt->mfc_stall, rte, rte_link); diff --git a/sys/netinet/raw_ip.c b/sys/netinet/raw_ip.c index b40ceb28..60824d92 100644 --- a/sys/netinet/raw_ip.c +++ b/sys/netinet/raw_ip.c @@ -343,17 +343,35 @@ rip_input(struct mbuf *m, int off) */ if (inp->inp_moptions != NULL && IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) { - struct sockaddr_in group; + /* + * If the incoming datagram is for IGMP, allow it + * through unconditionally to the raw socket. + * + * In the case of IGMPv2, we may not have explicitly + * joined the group, and may have set IFF_ALLMULTI + * on the interface. imo_multi_filter() may discard + * control traffic we actually need to see. + * + * Userland multicast routing daemons should continue + * filter the control traffic appropriately. + */ int blocked; - bzero(&group, sizeof(struct sockaddr_in)); - group.sin_len = sizeof(struct sockaddr_in); - group.sin_family = AF_INET; - group.sin_addr = ip->ip_dst; + blocked = MCAST_PASS; + if (proto != IPPROTO_IGMP) { + struct sockaddr_in group; + + bzero(&group, sizeof(struct sockaddr_in)); + group.sin_len = sizeof(struct sockaddr_in); + group.sin_family = AF_INET; + group.sin_addr = ip->ip_dst; + + blocked = imo_multi_filter(inp->inp_moptions, + ifp, + (struct sockaddr *)&group, + (struct sockaddr *)&ripsrc); + } - blocked = imo_multi_filter(inp->inp_moptions, ifp, - (struct sockaddr *)&group, - (struct sockaddr *)&ripsrc); if (blocked != MCAST_PASS) { IPSTAT_INC(ips_notmember); continue; diff --git a/sys/netinet/sctp_input.c b/sys/netinet/sctp_input.c index 4a916265..01b14570 100644 --- a/sys/netinet/sctp_input.c +++ b/sys/netinet/sctp_input.c @@ -834,6 +834,9 @@ sctp_handle_shutdown(struct sctp_shutdown_chunk *cp, return; } else { sctp_update_acked(stcb, cp, net, abort_flag); + if (*abort_flag) { + return; + } } if (asoc->control_pdapi) { /* diff --git a/sys/netinet6/raw_ip6.c b/sys/netinet6/raw_ip6.c index 108742d5..335eff54 100644 --- a/sys/netinet6/raw_ip6.c +++ b/sys/netinet6/raw_ip6.c @@ -213,17 +213,39 @@ rip6_input(struct mbuf **mp, int *offp, int proto) */ if (in6p->in6p_moptions && IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { - struct sockaddr_in6 mcaddr; + /* + * If the incoming datagram is for MLD, allow it + * through unconditionally to the raw socket. + * + * Use the M_RTALERT_MLD flag to check for MLD + * traffic without having to inspect the mbuf chain + * more deeply, as all MLDv1/v2 host messages MUST + * contain the Router Alert option. + * + * In the case of MLDv1, we may not have explicitly + * joined the group, and may have set IFF_ALLMULTI + * on the interface. im6o_mc_filter() may discard + * control traffic we actually need to see. + * + * Userland multicast routing daemons should continue + * filter the control traffic appropriately. + */ int blocked; - bzero(&mcaddr, sizeof(struct sockaddr_in6)); - mcaddr.sin6_len = sizeof(struct sockaddr_in6); - mcaddr.sin6_family = AF_INET6; - mcaddr.sin6_addr = ip6->ip6_dst; + blocked = MCAST_PASS; + if ((m->m_flags & M_RTALERT_MLD) == 0) { + struct sockaddr_in6 mcaddr; - blocked = im6o_mc_filter(in6p->in6p_moptions, ifp, - (struct sockaddr *)&mcaddr, - (struct sockaddr *)&fromsa); + bzero(&mcaddr, sizeof(struct sockaddr_in6)); + mcaddr.sin6_len = sizeof(struct sockaddr_in6); + mcaddr.sin6_family = AF_INET6; + mcaddr.sin6_addr = ip6->ip6_dst; + + blocked = im6o_mc_filter(in6p->in6p_moptions, + ifp, + (struct sockaddr *)&mcaddr, + (struct sockaddr *)&fromsa); + } if (blocked != MCAST_PASS) { IP6STAT_INC(ip6s_notmember); continue; diff --git a/sys/rpc/clnt_vc.c b/sys/rpc/clnt_vc.c index 85e89abe..2e5fe41f 100644 --- a/sys/rpc/clnt_vc.c +++ b/sys/rpc/clnt_vc.c @@ -413,6 +413,22 @@ call_again: cr->cr_xid = xid; mtx_lock(&ct->ct_lock); + /* + * Check to see if the other end has already started to close down + * the connection. The upcall will have set ct_error.re_status + * to RPC_CANTRECV if this is the case. + * If the other end starts to close down the connection after this + * point, it will be detected later when cr_error is checked, + * since the request is in the ct_pending queue. + */ + if (ct->ct_error.re_status == RPC_CANTRECV) { + if (errp != &ct->ct_error) { + errp->re_errno = ct->ct_error.re_errno; + errp->re_status = RPC_CANTRECV; + } + stat = RPC_CANTRECV; + goto out; + } TAILQ_INSERT_TAIL(&ct->ct_pending, cr, cr_link); mtx_unlock(&ct->ct_lock); -- 2.42.0