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