aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon L. B. Nielsen <simon@FreeBSD.org>2010-01-06 21:45:30 +0000
committerSimon L. B. Nielsen <simon@FreeBSD.org>2010-01-06 21:45:30 +0000
commit2e7e77ff792417b708755984259bd4833608e85b (patch)
tree310a76f9a643dfc68cb64eb2dce841ad7d4ada91
parent1cc4828b9a0d73fd006e657010e9d74108c7033b (diff)
downloadsrc-2e7e77ff792417b708755984259bd4833608e85b.tar.gz
src-2e7e77ff792417b708755984259bd4833608e85b.zip
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)
Notes
Notes: svn path=/releng/8.0/; revision=201679
-rw-r--r--UPDATING11
-rw-r--r--contrib/bind9/bin/named/query.c66
-rw-r--r--contrib/bind9/lib/dns/include/dns/types.h32
-rw-r--r--contrib/bind9/lib/dns/masterdump.c3
-rw-r--r--contrib/bind9/lib/dns/rbtdb.c4
-rw-r--r--contrib/bind9/lib/dns/resolver.c31
-rw-r--r--contrib/bind9/lib/dns/validator.c10
-rw-r--r--contrib/ntp/ntpd/ntp_request.c11
-rw-r--r--sys/cddl/compat/opensolaris/sys/vnode.h2
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_replay.c12
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c30
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c39
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/sys/vnode.h1
-rw-r--r--sys/conf/newvers.sh2
-rw-r--r--sys/kern/vfs_lookup.c6
-rw-r--r--sys/netinet/ip_mroute.c9
-rw-r--r--sys/netinet/raw_ip.c34
-rw-r--r--sys/netinet/sctp_input.c3
-rw-r--r--sys/netinet6/raw_ip6.c38
-rw-r--r--sys/rpc/clnt_vc.c16
20 files changed, 273 insertions, 87 deletions
diff --git a/UPDATING b/UPDATING
index a1089fa9274d..a2a59f221574 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 ffd9b3554a76..3f13347e419c 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 e07a7965bffb..73a6e322b41d 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 5eac96ff2807..84f3d276eeb0 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 9741c157f784..201fc39163fe 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 a5d7c2500f8f..0d513b29d39b 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 c62b714162ba..a6f8302bd12d 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 b1bc99d6f3f8..67bad2a8b9fd 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 7611a3f82011..7296635cc15b 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 573a82c98e19..658e53998c9c 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 a58f76e4b8d2..564871f69293 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 c43a8500818a..7157930f729b 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 a46b71187354..5f1f4b457fd8 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 eae90b134c65..de53cd7f4f8e 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 e553ae4dc064..51985622079d 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 39c71b06c060..48d5ffc03cb9 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 b40ceb28b792..60824d92697d 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 4a916265b9e7..01b145703e70 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 108742d55b65..335eff549393 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 85e89abe5c31..2e5fe41f1b94 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);