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, &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,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;