Print this page
MFV: illumos-gate@68c34d0407d130a7e8cb7dfb5394a985db03d785
9951 hook_stack_notify_unregister can leave stack locked
Reviewed by: Andy Fiddaman <omnios@citrus-it.net>
Reviewed by: Igor Kozhukhov <igor@dilos.org>
Reviewed by: Yuri Pankov <yuripv@yuripv.net>
Approved by: Dan McDonald <danmcd@joyent.com>
Author: Jason King <jason.king@joyent.com>


   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  *
  25  * Copyright 2013 Joyent, Inc.  All rights reserved.
  26  * Copyright (c) 2016 by Delphix. All rights reserved.
  27  */
  28 #include <sys/param.h>
  29 #include <sys/types.h>
  30 #include <sys/systm.h>
  31 #include <sys/errno.h>
  32 #include <sys/kmem.h>
  33 #include <sys/mutex.h>
  34 #include <sys/condvar.h>
  35 #include <sys/modctl.h>
  36 #include <sys/hook_impl.h>
  37 #include <sys/sdt.h>
  38 #include <sys/cmn_err.h>
  39 
  40 /*
  41  * This file provides kernel hook framework.
  42  */
  43 
  44 static struct modldrv modlmisc = {
  45         &mod_miscops,                               /* drv_modops */


 690         return (error);
 691 }
 692 
 693 /*
 694  * Function:    hook_stack_notify_unregister
 695  * Returns:     int         - 0 = success, else failure
 696  * Parameters:  stackid(I)  - netstack identifier
 697  *              callback(I) - function to be called
 698  *
 699  * Attempt to remove a registered function from a hook stack's list of
 700  * callbacks to activiate when protocols are added/deleted.
 701  * As with hook_stack_notify_register, if all things are going well then
 702  * a fake unregister event is delivered to the callback being removed
 703  * for each hook family that presently exists.
 704  */
 705 int
 706 hook_stack_notify_unregister(netstackid_t stackid, hook_notify_fn_t callback)
 707 {
 708         hook_family_int_t *hfi;
 709         hook_stack_t *hks;
 710         boolean_t canrun;
 711         char buffer[16];
 712         void *arg;
 713         int error;
 714 
 715         mutex_enter(&hook_stack_lock);
 716         hks = hook_stack_get(stackid);
 717         if (hks != NULL) {




 718                 CVW_ENTER_WRITE(&hks->hks_lock);
 719                 canrun = (hook_wait_setflag(&hks->hks_waiter, FWF_ADD_WAIT_MASK,
 720                     FWF_ADD_WANTED, FWF_ADD_ACTIVE) != -1);













 721 
 722                 error = hook_notify_unregister(&hks->hks_nhead, callback, &arg);
 723                 CVW_EXIT_WRITE(&hks->hks_lock);
 724         } else {
 725                 error = ESRCH;
 726         }
 727         mutex_exit(&hook_stack_lock);
 728 
 729         if (error == 0) {
 730                 if (canrun) {
 731                         /*
 732                          * Generate fake unregister event for callback that
 733                          * is being removed, letting it know everything that
 734                          * currently exists is now "disappearing."
 735                          */
 736                         (void) snprintf(buffer, sizeof (buffer), "%u",
 737                             hks->hks_netstackid);
 738 
 739                         SLIST_FOREACH(hfi, &hks->hks_familylist, hfi_entry) {
 740                                 callback(HN_UNREGISTER, arg, buffer, NULL,
 741                                     hfi->hfi_family.hf_name);
 742                         }
 743 
 744                         hook_wait_unsetflag(&hks->hks_waiter, FWF_ADD_ACTIVE);




 745                 }
 746 
 747                 mutex_enter(&hook_stack_lock);
 748                 hks = hook_stack_get(stackid);
 749                 if ((error == 0) && (hks->hks_shutdown == 2))
 750                         hook_stack_remove(hks);
 751                 mutex_exit(&hook_stack_lock);
 752         }
 753 
 754         return (error);
 755 }
 756 
 757 /*
 758  * Function:    hook_stack_notify_run
 759  * Returns:     None
 760  * Parameters:  hks(I)  - hook stack pointer to execute callbacks for
 761  *              name(I) - name of a hook family
 762  *              cmd(I)  - either HN_UNREGISTER or HN_REGISTER
 763  *
 764  * Run through the list of callbacks on the hook stack to be called when
 765  * a new hook family is added
 766  *
 767  * As hook_notify_run() expects 3 names, one for the family that is associated
 768  * with the cmd (HN_REGISTER or HN_UNREGISTER), one for the event and one
 769  * for the object being introduced and we really only have one name (that
 770  * of the new hook family), fake the hook stack's name by converting the
 771  * integer to a string and for the event just pass NULL.
 772  */




   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  *
  25  * Copyright 2018 Joyent, Inc.  All rights reserved.
  26  * Copyright (c) 2016 by Delphix. All rights reserved.
  27  */
  28 #include <sys/param.h>
  29 #include <sys/types.h>
  30 #include <sys/systm.h>
  31 #include <sys/errno.h>
  32 #include <sys/kmem.h>
  33 #include <sys/mutex.h>
  34 #include <sys/condvar.h>
  35 #include <sys/modctl.h>
  36 #include <sys/hook_impl.h>
  37 #include <sys/sdt.h>
  38 #include <sys/cmn_err.h>
  39 
  40 /*
  41  * This file provides kernel hook framework.
  42  */
  43 
  44 static struct modldrv modlmisc = {
  45         &mod_miscops,                               /* drv_modops */


 690         return (error);
 691 }
 692 
 693 /*
 694  * Function:    hook_stack_notify_unregister
 695  * Returns:     int         - 0 = success, else failure
 696  * Parameters:  stackid(I)  - netstack identifier
 697  *              callback(I) - function to be called
 698  *
 699  * Attempt to remove a registered function from a hook stack's list of
 700  * callbacks to activiate when protocols are added/deleted.
 701  * As with hook_stack_notify_register, if all things are going well then
 702  * a fake unregister event is delivered to the callback being removed
 703  * for each hook family that presently exists.
 704  */
 705 int
 706 hook_stack_notify_unregister(netstackid_t stackid, hook_notify_fn_t callback)
 707 {
 708         hook_family_int_t *hfi;
 709         hook_stack_t *hks;

 710         char buffer[16];
 711         void *arg;
 712         int error;
 713 
 714         mutex_enter(&hook_stack_lock);
 715         hks = hook_stack_get(stackid);
 716         if (hks == NULL) {
 717                 mutex_exit(&hook_stack_lock);
 718                 return (ESRCH);
 719         }
 720 
 721         CVW_ENTER_WRITE(&hks->hks_lock);
 722         /*
 723          * If hook_wait_setflag returns -1, another thread has flagged that it
 724          * is attempting to destroy this hook stack.  Before it can flag that
 725          * it's destroying the hook stack, it must first verify (with
 726          * hook_stack_lock held) that the hook stack is empty.  If we
 727          * encounter this, it means we should have nothing to do and we
 728          * just snuck in.
 729          */
 730         if (hook_wait_setflag(&hks->hks_waiter, FWF_DEL_WAIT_MASK,
 731             FWF_DEL_WANTED, FWF_DEL_ACTIVE) == -1) {
 732                 VERIFY(TAILQ_EMPTY(&hks->hks_nhead));
 733                 CVW_EXIT_WRITE(&hks->hks_lock);
 734                 mutex_exit(&hook_stack_lock);
 735                 return (ESRCH);
 736         }
 737 
 738         error = hook_notify_unregister(&hks->hks_nhead, callback, &arg);
 739         CVW_EXIT_WRITE(&hks->hks_lock);



 740         mutex_exit(&hook_stack_lock);
 741 
 742         if (error == 0) {

 743                 /*
 744                  * Generate fake unregister event for callback that
 745                  * is being removed, letting it know everything that
 746                  * currently exists is now "disappearing."
 747                  */
 748                 (void) snprintf(buffer, sizeof (buffer), "%u",
 749                     hks->hks_netstackid);
 750 
 751                 SLIST_FOREACH(hfi, &hks->hks_familylist, hfi_entry) {
 752                         callback(HN_UNREGISTER, arg, buffer, NULL,
 753                             hfi->hfi_family.hf_name);
 754                 }
 755         } else {
 756                 /*
 757                  * hook_notify_unregister() should only fail if the callback has
 758                  * already been deleted (ESRCH).
 759                  */
 760                 VERIFY3S(error, ==, ESRCH);
 761         }
 762 
 763         mutex_enter(&hook_stack_lock);
 764         hook_wait_unsetflag(&hks->hks_waiter, FWF_DEL_ACTIVE);
 765         if (hks->hks_shutdown == 2)
 766                 hook_stack_remove(hks);
 767         mutex_exit(&hook_stack_lock);

 768 
 769         return (error);
 770 }
 771 
 772 /*
 773  * Function:    hook_stack_notify_run
 774  * Returns:     None
 775  * Parameters:  hks(I)  - hook stack pointer to execute callbacks for
 776  *              name(I) - name of a hook family
 777  *              cmd(I)  - either HN_UNREGISTER or HN_REGISTER
 778  *
 779  * Run through the list of callbacks on the hook stack to be called when
 780  * a new hook family is added
 781  *
 782  * As hook_notify_run() expects 3 names, one for the family that is associated
 783  * with the cmd (HN_REGISTER or HN_UNREGISTER), one for the event and one
 784  * for the object being introduced and we really only have one name (that
 785  * of the new hook family), fake the hook stack's name by converting the
 786  * integer to a string and for the event just pass NULL.
 787  */