Print this page
7029 want per-process exploit mitigation features (secflags)
7030 want basic address space layout randomization (aslr)
7031 noexec_user_stack should be a secflag
7032 want a means to forbid mappings around NULL.

@@ -51,10 +51,11 @@
  */
 
 #include <sys/mntent.h>
 #include <sys/varargs.h>
 #include <sys/sysmacros.h>
+#include <sys/secflags.h>
 
 #include <errno.h>
 #include <fcntl.h>
 #include <strings.h>
 #include <unistd.h>

@@ -185,10 +186,11 @@
         "capped-cpu",
         "hostid",
         "admin",
         "fs-allowed",
         ALIAS_MAXPROCS,
+        "security-flags",
         NULL
 };
 
 /* These *must* match the order of the PT_ define's from zonecfg.h */
 char *prop_types[] = {

@@ -232,10 +234,13 @@
         "user",
         "auths",
         "fs-allowed",
         ALIAS_MAXPROCS,
         "allowed-address",
+        "default",
+        "lower",
+        "upper",
         NULL
 };
 
 /* These *must* match the order of the PROP_VAL_ define's from zonecfg.h */
 static char *prop_val_types[] = {

@@ -280,10 +285,11 @@
         "add dataset",
         "add dedicated-cpu",
         "add capped-cpu",
         "add capped-memory",
         "add admin",
+        "add security-flags",
         NULL
 };
 
 static const char *clear_cmds[] = {
         "clear autoboot",

@@ -311,10 +317,11 @@
         "remove dataset ",
         "remove dedicated-cpu ",
         "remove capped-cpu ",
         "remove capped-memory ",
         "remove admin ",
+        "remove security-flags",
         NULL
 };
 
 static const char *select_cmds[] = {
         "select fs ",

@@ -325,10 +332,11 @@
         "select dataset ",
         "select dedicated-cpu",
         "select capped-cpu",
         "select capped-memory",
         "select admin",
+        "select security-flags",
         NULL
 };
 
 static const char *set_cmds[] = {
         "set zonename=",

@@ -360,10 +368,11 @@
         "info attr ",
         "info dataset ",
         "info capped-memory",
         "info dedicated-cpu",
         "info capped-cpu",
+        "info security-flags",
         "info zonename",
         "info zonepath",
         "info autoboot",
         "info pool",
         "info limitpriv",

@@ -502,10 +511,20 @@
         "set user=",
         "set auths=",
         NULL
 };
 
+static const char *secflags_res_scope_cmds[] = {
+        "cancel",
+        "end",
+        "exit",
+        "set default=",
+        "set lower=",
+        "set upper=",
+        NULL
+};
+
 struct xif {
         struct xif      *xif_next;
         char            xif_name[LIFNAMSIZ];
         boolean_t       xif_has_address;
         boolean_t       xif_has_defrouter;

@@ -579,10 +598,11 @@
 static struct zone_attrtab      old_attrtab, in_progress_attrtab;
 static struct zone_dstab        old_dstab, in_progress_dstab;
 static struct zone_psettab      old_psettab, in_progress_psettab;
 static struct zone_mcaptab      old_mcaptab, in_progress_mcaptab;
 static struct zone_admintab     old_admintab, in_progress_admintab;
+static struct zone_secflagstab  old_secflagstab, in_progress_secflagstab;
 
 static GetLine *gl;     /* The gl_get_line() resource object */
 
 static void bytes_to_units(char *str, char *buf, int bufsize);
 

@@ -656,10 +676,14 @@
                 return (add_stuff(cpl, line, pcap_res_scope_cmds, word_end));
         case RT_MCAP:
                 return (add_stuff(cpl, line, mcap_res_scope_cmds, word_end));
         case RT_ADMIN:
                 return (add_stuff(cpl, line, admin_res_scope_cmds, word_end));
+        case RT_SECFLAGS:
+                return (add_stuff(cpl, line, secflags_res_scope_cmds,
+                    word_end));
+
         }
         return (0);
 }
 
 /*

@@ -971,11 +995,12 @@
 
         return (-1);
 }
 
 static FILE *
-pager_open(void) {
+pager_open(void)
+{
         FILE *newfp;
         char *pager, *space;
 
         pager = getenv("PAGER");
         if (pager == NULL || *pager == '\0')

@@ -997,11 +1022,12 @@
         }
         return (NULL);
 }
 
 static void
-pager_close(FILE *fp) {
+pager_close(FILE *fp)
+{
         int status;
 
         status = pclose(fp);
         if (status == -1)
                 zerr(gettext("PAGER close failed (%s)."),

@@ -1225,10 +1251,25 @@
                             gettext("<single user or role name>"));
                         (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
                             pt_to_str(PT_AUTHS),
                             gettext("<comma separated list>"));
                         break;
+                case RT_SECFLAGS:
+                        (void) fprintf(fp, gettext("The '%s' resource scope is "
+                            "used to specify the default security-flags\n"
+                            "of this zone, and their upper and lower bound.\n"),
+                            rt_to_str(resource_scope));
+                        (void) fprintf(fp, "\t%s %s=%s\n",
+                            cmd_to_str(CMD_SET), pt_to_str(PT_DEFAULT),
+                            gettext("<security flags>"));
+                        (void) fprintf(fp, "\t%s %s=%s\n",
+                            cmd_to_str(CMD_SET), pt_to_str(PT_LOWER),
+                            gettext("<security flags>"));
+                        (void) fprintf(fp, "\t%s %s=%s\n",
+                            cmd_to_str(CMD_SET), pt_to_str(PT_UPPER),
+                            gettext("<security flags>"));
+                        break;
                 }
                 (void) fprintf(fp, gettext("And from any resource scope, you "
                     "can:\n"));
                 (void) fprintf(fp, "\t%s\t%s\n", cmd_to_str(CMD_END),
                     gettext("(to conclude this operation)"));

@@ -1289,11 +1330,11 @@
                     gettext("resource type"), rt_to_str(RT_FS),
                     rt_to_str(RT_NET), rt_to_str(RT_DEVICE),
                     rt_to_str(RT_RCTL), rt_to_str(RT_ATTR),
                     rt_to_str(RT_DATASET), rt_to_str(RT_DCPU),
                     rt_to_str(RT_PCAP), rt_to_str(RT_MCAP),
-                    rt_to_str(RT_ADMIN));
+                    rt_to_str(RT_ADMIN), rt_to_str(RT_SECFLAGS));
         }
         if (flags & HELP_PROPS) {
                 (void) fprintf(fp, gettext("For resource type ... there are "
                     "property types ...:\n"));
                 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),

@@ -1355,10 +1396,13 @@
                 (void) fprintf(fp, "\t%s\t%s, %s, %s\n", rt_to_str(RT_MCAP),
                     pt_to_str(PT_PHYSICAL), pt_to_str(PT_SWAP),
                     pt_to_str(PT_LOCKED));
                 (void) fprintf(fp, "\t%s\t\t%s, %s\n", rt_to_str(RT_ADMIN),
                     pt_to_str(PT_USER), pt_to_str(PT_AUTHS));
+                (void) fprintf(fp, "\t%s\t\t%s, %s, %s\n",
+                    rt_to_str(RT_SECFLAGS), pt_to_str(PT_DEFAULT),
+                    pt_to_str(PT_LOWER), pt_to_str(PT_UPPER));
         }
         if (need_to_close)
                 (void) pager_close(fp);
 }
 

@@ -1798,10 +1842,11 @@
         struct zone_dstab dstab;
         struct zone_psettab psettab;
         struct zone_mcaptab mcaptab;
         struct zone_rctlvaltab *valptr;
         struct zone_admintab admintab;
+        struct zone_secflagstab secflagstab;
         int err, arg;
         char zonepath[MAXPATHLEN], outfile[MAXPATHLEN], pool[MAXNAMELEN];
         char bootargs[BOOTARGS_MAX];
         char sched[MAXNAMELEN];
         char brand[MAXNAMELEN];

@@ -2067,12 +2112,25 @@
                     rt_to_str(RT_ADMIN));
                 export_prop(of, PT_USER, admintab.zone_admin_user);
                 export_prop(of, PT_AUTHS, admintab.zone_admin_auths);
                 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
         }
+
         (void) zonecfg_endadminent(handle);
 
+        if ((err = zonecfg_getsecflagsent(handle, &secflagstab)) != Z_OK) {
+                zone_perror(zone, err, B_FALSE);
+                goto done;
+        }
+
+        (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD),
+            rt_to_str(RT_SECFLAGS));
+        export_prop(of, PT_DEFAULT, secflagstab.zone_secflags_default);
+        export_prop(of, PT_LOWER, secflagstab.zone_secflags_lower);
+        export_prop(of, PT_UPPER, secflagstab.zone_secflags_upper);
+        (void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
+
         /*
          * There is nothing to export for pcap since this resource is just
          * a container for an rctl alias.
          */
 

@@ -2148,10 +2206,11 @@
 add_resource(cmd_t *cmd)
 {
         int type;
         struct zone_psettab tmp_psettab;
         struct zone_mcaptab tmp_mcaptab;
+        struct zone_secflagstab tmp_secflagstab;
         uint64_t tmp;
         uint64_t tmp_mcap;
         char pool[MAXNAMELEN];
 
         if ((type = cmd->cmd_res_type) == RT_UNKNOWN) {

@@ -2259,10 +2318,18 @@
                 bzero(&in_progress_mcaptab, sizeof (in_progress_mcaptab));
                 return;
         case RT_ADMIN:
                 bzero(&in_progress_admintab, sizeof (in_progress_admintab));
                 return;
+        case RT_SECFLAGS:
+                /* Make sure we haven't already set this */
+                if (zonecfg_lookup_secflags(handle, &tmp_secflagstab) == Z_OK)
+                        zerr(gettext("The %s resource already exists."),
+                            rt_to_str(RT_SECFLAGS));
+                bzero(&in_progress_secflagstab,
+                    sizeof (in_progress_secflagstab));
+                return;
         default:
                 zone_perror(rt_to_str(type), Z_NO_RESOURCE_TYPE, B_TRUE);
                 long_usage(CMD_ADD, B_TRUE);
                 usage(B_FALSE, HELP_RESOURCES);
         }

@@ -2928,10 +2995,58 @@
                 return (Z_OK);
         err = zonecfg_lookup_admin(handle, admintab);
         return (err);
 }
 
+static int
+fill_in_secflagstab(cmd_t *cmd, struct zone_secflagstab *secflagstab,
+    boolean_t fill_in_only)
+{
+        int err, i;
+        property_value_ptr_t pp;
+
+        if ((err = initialize(B_TRUE)) != Z_OK)
+                return (err);
+
+        bzero(secflagstab, sizeof (*secflagstab));
+        for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
+                pp = cmd->cmd_property_ptr[i];
+                if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) {
+                        zerr(gettext("A simple value was expected here."));
+                        saw_error = B_TRUE;
+                        return (Z_INSUFFICIENT_SPEC);
+                }
+                switch (cmd->cmd_prop_name[i]) {
+                case PT_DEFAULT:
+                        (void) strlcpy(secflagstab->zone_secflags_default,
+                            pp->pv_simple,
+                            sizeof (secflagstab->zone_secflags_default));
+                        break;
+                case PT_LOWER:
+                        (void) strlcpy(secflagstab->zone_secflags_lower,
+                            pp->pv_simple,
+                            sizeof (secflagstab->zone_secflags_lower));
+                        break;
+                case PT_UPPER:
+                        (void) strlcpy(secflagstab->zone_secflags_upper,
+                            pp->pv_simple,
+                            sizeof (secflagstab->zone_secflags_upper));
+                        break;
+                default:
+                        zone_perror(pt_to_str(cmd->cmd_prop_name[i]),
+                            Z_NO_PROPERTY_TYPE, B_TRUE);
+                        return (Z_INSUFFICIENT_SPEC);
+                }
+        }
+        if (fill_in_only)
+                return (Z_OK);
+
+        err = zonecfg_lookup_secflags(handle, secflagstab);
+
+        return (err);
+}
+
 static void
 remove_aliased_rctl(int type, char *name)
 {
         int err;
         uint64_t tmp;

@@ -3330,10 +3445,31 @@
                         need_to_commit = B_TRUE;
         }
 }
 
 static void
+remove_secflags()
+{
+        int err;
+        struct zone_secflagstab sectab = { 0 };
+
+        if (zonecfg_lookup_secflags(handle, &sectab) != Z_OK) {
+                zerr("%s %s: %s", cmd_to_str(CMD_REMOVE),
+                    rt_to_str(RT_SECFLAGS),
+                    zonecfg_strerror(Z_NO_RESOURCE_TYPE));
+                return;
+        }
+
+        if ((err = zonecfg_delete_secflags(handle, &sectab)) != Z_OK) {
+                z_cmd_rt_perror(CMD_REMOVE, RT_SECFLAGS, err, B_TRUE);
+                return;
+        }
+
+        need_to_commit = B_TRUE;
+}
+
+static void
 remove_resource(cmd_t *cmd)
 {
         int type;
         int arg;
         boolean_t arg_err = B_FALSE;

@@ -3393,10 +3529,13 @@
                 remove_mcap();
                 return;
         case RT_ADMIN:
                 remove_admin(cmd);
                 return;
+        case RT_SECFLAGS:
+                remove_secflags();
+                return;
         default:
                 zone_perror(rt_to_str(type), Z_NO_RESOURCE_TYPE, B_TRUE);
                 long_usage(CMD_REMOVE, B_TRUE);
                 usage(B_FALSE, HELP_RESOURCES);
                 return;

@@ -3605,10 +3744,26 @@
                 case PT_LOCKED:
                         remove_aliased_rctl(PT_LOCKED, ALIAS_MAXLOCKEDMEM);
                         return;
                 }
                 break;
+        case RT_SECFLAGS:
+                switch (prop_type) {
+                case PT_LOWER:
+                        in_progress_secflagstab.zone_secflags_lower[0] = '\0';
+                        need_to_commit = B_TRUE;
+                        return;
+                case PT_DEFAULT:
+                        in_progress_secflagstab.zone_secflags_default[0] = '\0';
+                        need_to_commit = B_TRUE;
+                        return;
+                case PT_UPPER:
+                        in_progress_secflagstab.zone_secflags_upper[0] = '\0';
+                        need_to_commit = B_TRUE;
+                        return;
+                }
+                break;
         default:
                 break;
         }
 
         zone_perror(pt_to_str(prop_type), Z_CLEAR_DISALLOW, B_TRUE);

@@ -3858,10 +4013,20 @@
                         global_scope = B_TRUE;
                 }
                 bcopy(&old_admintab, &in_progress_admintab,
                     sizeof (struct zone_admintab));
                 return;
+        case RT_SECFLAGS:
+                if ((err = fill_in_secflagstab(cmd, &old_secflagstab, B_FALSE))
+                    != Z_OK) {
+                        z_cmd_rt_perror(CMD_SELECT, RT_SECFLAGS, err,
+                            B_TRUE);
+                        global_scope = B_TRUE;
+                }
+                bcopy(&old_secflagstab, &in_progress_secflagstab,
+                    sizeof (struct zone_secflagstab));
+                return;
         default:
                 zone_perror(rt_to_str(type), Z_NO_RESOURCE_TYPE, B_TRUE);
                 long_usage(CMD_SELECT, B_TRUE);
                 usage(B_FALSE, HELP_RESOURCES);
                 return;

@@ -4774,10 +4939,33 @@
                             B_TRUE);
                         long_usage(CMD_SET, B_TRUE);
                         usage(B_FALSE, HELP_PROPS);
                         return;
                 }
+        case RT_SECFLAGS: {
+                char *propstr;
+
+                switch (prop_type) {
+                case PT_DEFAULT:
+                        propstr = in_progress_secflagstab.zone_secflags_default;
+                        break;
+                case PT_UPPER:
+                        propstr = in_progress_secflagstab.zone_secflags_upper;
+                        break;
+                case PT_LOWER:
+                        propstr = in_progress_secflagstab.zone_secflags_lower;
+                        break;
+                default:
+                        zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
+                            B_TRUE);
+                        long_usage(CMD_SET, B_TRUE);
+                        usage(B_FALSE, HELP_PROPS);
+                        return;
+                }
+                (void) strlcpy(propstr, prop_id, ZONECFG_SECFLAGS_MAX);
+                return;
+        }
         default:
                 zone_perror(rt_to_str(res_type), Z_NO_RESOURCE_TYPE, B_TRUE);
                 long_usage(CMD_SET, B_TRUE);
                 usage(B_FALSE, HELP_RESOURCES);
                 return;

@@ -5388,10 +5576,19 @@
         output_prop(fp, PT_USER, admintab->zone_admin_user, B_TRUE);
         output_prop(fp, PT_AUTHS, admintab->zone_admin_auths, B_TRUE);
 }
 
 static void
+output_secflags(FILE *fp, struct zone_secflagstab *sftab)
+{
+        (void) fprintf(fp, "%s:\n", rt_to_str(RT_SECFLAGS));
+        output_prop(fp, PT_DEFAULT, sftab->zone_secflags_default, B_TRUE);
+        output_prop(fp, PT_LOWER, sftab->zone_secflags_lower, B_TRUE);
+        output_prop(fp, PT_UPPER, sftab->zone_secflags_upper, B_TRUE);
+}
+
+static void
 info_auth(zone_dochandle_t handle, FILE *fp, cmd_t *cmd)
 {
         struct zone_admintab lookup, user;
         boolean_t output = B_FALSE;
         int err;

@@ -5421,10 +5618,24 @@
         if (!output && cmd->cmd_prop_nv_pairs > 0)
                 (void) printf(gettext("No such %s resource.\n"),
                     rt_to_str(RT_ADMIN));
 }
 
+static void
+info_secflags(zone_dochandle_t handle, FILE *fp)
+{
+        struct zone_secflagstab sftab;
+        int err;
+
+        if ((err = zonecfg_lookup_secflags(handle, &sftab)) != Z_OK) {
+                zone_perror(zone, err, B_TRUE);
+                return;
+        }
+
+        output_secflags(fp, &sftab);
+}
+
 void
 info_func(cmd_t *cmd)
 {
         FILE *fp = stdout;
         boolean_t need_to_close = B_FALSE;

@@ -5483,10 +5694,13 @@
                             res2, locked_limit);
                         break;
                 case RT_ADMIN:
                         output_auth(fp, &in_progress_admintab);
                         break;
+                case RT_SECFLAGS:
+                        output_secflags(fp, &in_progress_secflagstab);
+                        break;
                 }
                 goto cleanup;
         }
 
         type = cmd->cmd_res_type;

@@ -5539,10 +5753,11 @@
                         info_attr(handle, fp, cmd);
                         info_ds(handle, fp, cmd);
                         info_auth(handle, fp, cmd);
                 }
                 info_rctl(handle, fp, cmd);
+                info_secflags(handle, fp);
                 break;
         case RT_ZONENAME:
                 info_zonename(handle, fp);
                 break;
         case RT_ZONEPATH:

@@ -5624,10 +5839,13 @@
                 info_auth(handle, fp, cmd);
                 break;
         case RT_FS_ALLOWED:
                 info_fs_allowed(handle, fp);
                 break;
+        case RT_SECFLAGS:
+                info_secflags(handle, fp);
+                break;
         default:
                 zone_perror(rt_to_str(cmd->cmd_res_type), Z_NO_RESOURCE_TYPE,
                     B_TRUE);
         }
 

@@ -5775,10 +5993,92 @@
         tmp->xif_next = xif;
         xif = tmp;
         return (B_TRUE);
 }
 
+boolean_t
+verify_secflags(struct zone_secflagstab *tab)
+{
+        secflagdelta_t def = {0};
+        secflagdelta_t upper = {0};
+        secflagdelta_t lower = {0};
+        boolean_t def_set = B_FALSE;
+        boolean_t upper_set = B_FALSE;
+        boolean_t lower_set = B_FALSE;
+        boolean_t ret = B_TRUE;
+
+        if (strlen(tab->zone_secflags_default) > 0) {
+                def_set = B_TRUE;
+                if (secflags_parse(NULL, tab->zone_secflags_default,
+                    &def) == -1) {
+                        zerr(gettext("default security flags '%s' are invalid"),
+                            tab->zone_secflags_default);
+                        ret = B_FALSE;
+                }
+        } else {
+                secflags_zero(&def.psd_assign);
+                def.psd_ass_active = B_TRUE;
+        }
+
+        if (strlen(tab->zone_secflags_upper) > 0) {
+                upper_set = B_TRUE;
+                if (secflags_parse(NULL, tab->zone_secflags_upper,
+                    &upper) == -1) {
+                        zerr(gettext("upper security flags '%s' are invalid"),
+                            tab->zone_secflags_upper);
+                        ret = B_FALSE;
+                }
+        } else {
+                secflags_fullset(&upper.psd_assign);
+                upper.psd_ass_active = B_TRUE;
+        }
+
+        if (strlen(tab->zone_secflags_lower) > 0) {
+                lower_set = B_TRUE;
+                if (secflags_parse(NULL, tab->zone_secflags_lower,
+                    &lower) == -1) {
+                        zerr(gettext("lower security flags '%s' are invalid"),
+                            tab->zone_secflags_lower);
+                        ret = B_FALSE;
+                }
+        } else {
+                secflags_zero(&lower.psd_assign);
+                lower.psd_ass_active = B_TRUE;
+        }
+
+        if (def_set && !def.psd_ass_active) {
+                zerr(gettext("only assignment of security flags is "
+                    "allowed (default: %s)"), tab->zone_secflags_default);
+        }
+
+        if (lower_set && !lower.psd_ass_active) {
+                zerr(gettext("only assignment of security flags is "
+                    "allowed (lower: %s)"), tab->zone_secflags_lower);
+        }
+
+        if (upper_set && !upper.psd_ass_active) {
+                zerr(gettext("only assignment of security flags is "
+                    "allowed (upper: %s)"), tab->zone_secflags_upper);
+        }
+
+        if (def.psd_assign & ~upper.psd_assign) { /* In default but not upper */
+                zerr(gettext("default secflags must be within the "
+                    "upper limit"));
+                ret = B_FALSE;
+        }
+        if (lower.psd_assign & ~def.psd_assign) { /* In lower but not default */
+                zerr(gettext("default secflags must be above the lower limit"));
+                ret = B_FALSE;
+        }
+        if (lower.psd_assign & ~upper.psd_assign) { /* In lower but not upper */
+                zerr(gettext("lower secflags must be within the upper limit"));
+                ret = B_FALSE;
+        }
+
+        return (ret);
+}
+
 /*
  * See the DTD for which attributes are required for which resources.
  *
  * This function can be called by commit_func(), which needs to save things,
  * in addition to the general call from parse_and_run(), which doesn't need

@@ -5794,10 +6094,11 @@
         struct zone_attrtab attrtab;
         struct zone_rctltab rctltab;
         struct zone_dstab dstab;
         struct zone_psettab psettab;
         struct zone_admintab admintab;
+        struct zone_secflagstab secflagstab;
         char zonepath[MAXPATHLEN];
         char sched[MAXNAMELEN];
         char brand[MAXNAMELEN];
         char hostidp[HW_HOSTID_LEN];
         char fsallowedp[ZONE_FS_ALLOWED_MAX];

@@ -6090,10 +6391,24 @@
                         ret_val = Z_BAD_PROPERTY;
                 }
         }
         (void) zonecfg_endadminent(handle);
 
+        if ((err = zonecfg_getsecflagsent(handle, &secflagstab)) != Z_OK) {
+                zone_perror(zone, err, B_TRUE);
+                return;
+        }
+
+        /*
+         * No properties are required, but any specified should be
+         * valid
+         */
+        if (verify_secflags(&secflagstab) != B_TRUE) {
+                /* Error is reported from verify_secflags */
+                ret_val = Z_BAD_PROPERTY;
+        }
+
         if (!global_scope) {
                 zerr(gettext("resource specification incomplete"));
                 saw_error = B_TRUE;
                 if (ret_val == Z_OK)
                         ret_val = Z_INSUFFICIENT_SPEC;

@@ -6679,10 +6994,24 @@
                         err = zonecfg_modify_admin(handle,
                             &old_admintab, &in_progress_admintab,
                             zone);
                 }
                 break;
+        case RT_SECFLAGS:
+                if (verify_secflags(&in_progress_secflagstab) != B_TRUE) {
+                        saw_error = B_TRUE;
+                        return;
+                }
+
+                if (end_op == CMD_ADD) {
+                        err = zonecfg_add_secflags(handle,
+                            &in_progress_secflagstab);
+                } else {
+                        err = zonecfg_modify_secflags(handle,
+                            &old_secflagstab, &in_progress_secflagstab);
+                }
+                break;
         default:
                 zone_perror(rt_to_str(resource_scope), Z_NO_RESOURCE_TYPE,
                     B_TRUE);
                 saw_error = B_TRUE;
                 return;