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,60 ****
--- 51,61 ----
*/
#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,194 ****
--- 186,196 ----
"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,241 ****
--- 234,246 ----
"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,289 ****
--- 285,295 ----
"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,320 ****
--- 317,327 ----
"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,334 ****
--- 332,342 ----
"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,369 ****
--- 368,378 ----
"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,511 ****
--- 511,530 ----
"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,588 ****
--- 598,608 ----
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,665 ****
--- 676,689 ----
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,981 ****
return (-1);
}
static FILE *
! pager_open(void) {
FILE *newfp;
char *pager, *space;
pager = getenv("PAGER");
if (pager == NULL || *pager == '\0')
--- 995,1006 ----
return (-1);
}
static FILE *
! pager_open(void)
! {
FILE *newfp;
char *pager, *space;
pager = getenv("PAGER");
if (pager == NULL || *pager == '\0')
*** 997,1007 ****
}
return (NULL);
}
static void
! pager_close(FILE *fp) {
int status;
status = pclose(fp);
if (status == -1)
zerr(gettext("PAGER close failed (%s)."),
--- 1022,1033 ----
}
return (NULL);
}
static void
! pager_close(FILE *fp)
! {
int status;
status = pclose(fp);
if (status == -1)
zerr(gettext("PAGER close failed (%s)."),
*** 1225,1234 ****
--- 1251,1275 ----
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,1299 ****
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));
}
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)"),
--- 1330,1340 ----
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_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,1364 ****
--- 1396,1408 ----
(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,1807 ****
--- 1842,1852 ----
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,2078 ****
--- 2112,2136 ----
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,2157 ****
--- 2206,2216 ----
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,2268 ****
--- 2318,2335 ----
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,2937 ****
--- 2995,3052 ----
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,3339 ****
--- 3445,3475 ----
need_to_commit = B_TRUE;
}
}
static void
+ remove_secflags()
+ {
+ int err;
+ struct zone_secflagstab sectab = { 0 };
+
+ if (zonecfg_lookup_secflags(handle, §ab) != 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, §ab)) != 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,3402 ****
--- 3529,3541 ----
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,3614 ****
--- 3744,3769 ----
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,3867 ****
--- 4013,4032 ----
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,4783 ****
--- 4939,4971 ----
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,5397 ****
--- 5576,5594 ----
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,5430 ****
--- 5618,5641 ----
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,5492 ****
--- 5694,5706 ----
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,5548 ****
--- 5753,5763 ----
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,5633 ****
--- 5839,5851 ----
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,5784 ****
--- 5993,6084 ----
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,5803 ****
--- 6094,6104 ----
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,6099 ****
--- 6391,6414 ----
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,6688 ****
--- 6994,7017 ----
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;