Print this page
1918 stack overflow from mac_promisc_dispatch()

@@ -18,10 +18,11 @@
  *
  * CDDL HEADER END
  */
 /*
  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2011, Nexenta Systems, Inc. All rights reserved.
  */
 
 /*
  * Data-Link Driver
  */

@@ -571,11 +572,11 @@
 proto_promiscon_req(dld_str_t *dsp, mblk_t *mp)
 {
         dl_promiscon_req_t *dlp = (dl_promiscon_req_t *)mp->b_rptr;
         int             err = 0;
         t_uscalar_t     dl_err;
-        uint32_t        promisc_saved;
+        uint32_t        new_flags, promisc_saved;
         queue_t         *q = dsp->ds_wq;
         mac_perim_handle_t      mph;
 
         if (MBLKL(mp) < sizeof (dl_promiscon_req_t)) {
                 dl_err = DL_BADPRIM;

@@ -586,41 +587,41 @@
             DL_ACK_PENDING(dsp->ds_dlstate)) {
                 dl_err = DL_OUTSTATE;
                 goto failed;
         }
 
-        promisc_saved = dsp->ds_promisc;
+        mac_perim_enter_by_mh(dsp->ds_mh, &mph);
+
+        new_flags = promisc_saved = dsp->ds_promisc;
         switch (dlp->dl_level) {
         case DL_PROMISC_SAP:
-                dsp->ds_promisc |= DLS_PROMISC_SAP;
+                new_flags |= DLS_PROMISC_SAP;
                 break;
 
         case DL_PROMISC_MULTI:
-                dsp->ds_promisc |= DLS_PROMISC_MULTI;
+                new_flags |= DLS_PROMISC_MULTI;
                 break;
 
         case DL_PROMISC_PHYS:
-                dsp->ds_promisc |= DLS_PROMISC_PHYS;
+                new_flags |= DLS_PROMISC_PHYS;
                 break;
 
         default:
                 dl_err = DL_NOTSUPPORTED;
                 goto failed;
         }
 
-        mac_perim_enter_by_mh(dsp->ds_mh, &mph);
-
         if ((promisc_saved == 0) && (err = dls_active_set(dsp)) != 0) {
-                dsp->ds_promisc = promisc_saved;
+                ASSERT(dsp->ds_promisc == promisc_saved);
                 dl_err = DL_SYSERR;
                 goto failed2;
         }
 
         /*
          * Adjust channel promiscuity.
          */
-        err = dls_promisc(dsp, promisc_saved);
+        err = dls_promisc(dsp, new_flags);
 
         if (err != 0) {
                 dl_err = DL_SYSERR;
                 dsp->ds_promisc = promisc_saved;
                 if (promisc_saved == 0)

@@ -646,11 +647,11 @@
 proto_promiscoff_req(dld_str_t *dsp, mblk_t *mp)
 {
         dl_promiscoff_req_t *dlp = (dl_promiscoff_req_t *)mp->b_rptr;
         int             err = 0;
         t_uscalar_t     dl_err;
-        uint32_t        promisc_saved;
+        uint32_t        new_flags;
         queue_t         *q = dsp->ds_wq;
         mac_perim_handle_t      mph;
 
         if (MBLKL(mp) < sizeof (dl_promiscoff_req_t)) {
                 dl_err = DL_BADPRIM;

@@ -661,53 +662,55 @@
             DL_ACK_PENDING(dsp->ds_dlstate)) {
                 dl_err = DL_OUTSTATE;
                 goto failed;
         }
 
-        promisc_saved = dsp->ds_promisc;
+        mac_perim_enter_by_mh(dsp->ds_mh, &mph);
+
+        new_flags = dsp->ds_promisc;
         switch (dlp->dl_level) {
         case DL_PROMISC_SAP:
                 if (!(dsp->ds_promisc & DLS_PROMISC_SAP)) {
                         dl_err = DL_NOTENAB;
                         goto failed;
                 }
-                dsp->ds_promisc &= ~DLS_PROMISC_SAP;
+                new_flags &= ~DLS_PROMISC_SAP;
                 break;
 
         case DL_PROMISC_MULTI:
                 if (!(dsp->ds_promisc & DLS_PROMISC_MULTI)) {
                         dl_err = DL_NOTENAB;
                         goto failed;
                 }
-                dsp->ds_promisc &= ~DLS_PROMISC_MULTI;
+                new_flags &= ~DLS_PROMISC_MULTI;
                 break;
 
         case DL_PROMISC_PHYS:
                 if (!(dsp->ds_promisc & DLS_PROMISC_PHYS)) {
                         dl_err = DL_NOTENAB;
                         goto failed;
                 }
-                dsp->ds_promisc &= ~DLS_PROMISC_PHYS;
+                new_flags &= ~DLS_PROMISC_PHYS;
                 break;
 
         default:
                 dl_err = DL_NOTSUPPORTED;
                 goto failed;
         }
 
-        mac_perim_enter_by_mh(dsp->ds_mh, &mph);
         /*
          * Adjust channel promiscuity.
          */
-        err = dls_promisc(dsp, promisc_saved);
+        err = dls_promisc(dsp, new_flags);
 
         if (err != 0) {
                 mac_perim_exit(mph);
                 dl_err = DL_SYSERR;
                 goto failed;
         }
 
+        ASSERT(dsp->ds_promisc == new_flags);
         if (dsp->ds_promisc == 0)
                 dls_active_clear(dsp, B_FALSE);
 
         mac_perim_exit(mph);