static context_t runcon_compute_new_context(char *user, char *role, char *type, char *range, char *command, int compute_trans) { context_t con; security_context_t cur_context; if (getcon(&cur_context)) bb_error_msg_and_die("can't get current context"); if (compute_trans) { security_context_t file_context, new_context; if (getfilecon(command, &file_context) < 0) bb_error_msg_and_die("can't retrieve attributes of '%s'", command); if (security_compute_create(cur_context, file_context, SECCLASS_PROCESS, &new_context)) bb_error_msg_and_die("unable to compute a new context"); cur_context = new_context; } con = context_new(cur_context); if (!con) bb_error_msg_and_die("'%s' is not a valid context", cur_context); if (user && context_user_set(con, user)) bb_error_msg_and_die("can't set new user '%s'", user); if (type && context_type_set(con, type)) bb_error_msg_and_die("can't set new type '%s'", type); if (range && context_range_set(con, range)) bb_error_msg_and_die("can't set new range '%s'", range); if (role && context_role_set(con, role)) bb_error_msg_and_die("can't set new role '%s'", role); return con; }
static int check_dominance(const char *pattern, const char *raw) { security_context_t ctx; context_t con; struct av_decision avd; int rc = -1; context_t my_tmp; const char *raw_range; security_class_t context_class = string_to_security_class("context"); access_vector_t context_contains_perm = string_to_av_perm(context_class, "contains"); con = context_new(raw); if (!con) return -1; raw_range = context_range_get(con); my_tmp = context_new(my_context); if (!my_tmp) { context_free(con); return -1; } ctx = NULL; if (context_range_set(my_tmp, pattern)) goto out; ctx = strdup(context_str(my_tmp)); if (!ctx) goto out; if (context_range_set(my_tmp, raw_range)) goto out; raw = context_str(my_tmp); if (!raw) goto out; rc = security_compute_av_raw(ctx, (security_context_t)raw, context_class, context_contains_perm, &avd); if (rc) goto out; rc = (context_contains_perm & avd.allowed) != context_contains_perm; out: free(ctx); context_free(my_tmp); context_free(con); return rc; }
static int set_context_from_socket( const struct service_config *scp, int fd ) { security_context_t curr_context = NULL; security_context_t peer_context = NULL; security_context_t exec_context = NULL; context_t bcon = NULL; context_t pcon = NULL; security_context_t new_context = NULL; security_context_t new_exec_context = NULL; int retval = -1; const char *exepath = NULL; if (getcon(&curr_context) < 0) goto fail; if (getpeercon(fd, &peer_context) < 0) goto fail; exepath = SC_SERVER_ARGV( scp )[0]; if (getfilecon(exepath, &exec_context) < 0) goto fail; if (!(bcon = context_new(curr_context))) goto fail; if (!(pcon = context_new(peer_context))) goto fail; if (!context_range_get(pcon)) goto fail; if (context_range_set(bcon, context_range_get(pcon))) goto fail; if (!(new_context = context_str(bcon))) goto fail; if (security_compute_create(new_context, exec_context, SECCLASS_PROCESS, &new_exec_context) < 0) goto fail; retval = set_context(new_exec_context); freecon(new_exec_context); fail: context_free(pcon); context_free(bcon); freecon(exec_context); freecon(peer_context); freecon(curr_context); return retval; }
/* Set the context of all files associated with this VM to the new context * complete with the unique generated category. */ static int file_con_fixup (data_t *data) { security_context_t sec_con = { 0, }; context_t con = { 0, }; char mcs_str[9] = { 0, }; int ret = 0, p_ret = 0, i = 0;; p_ret = snprintf (mcs_str, sizeof (mcs_str), "s0:c%d", data->category); if (p_ret < 0 || p_ret > 9) { syslog (LOG_CRIT, "insufficient buffer size"); return -1; } for (i = 0; data->files [i] != NULL; ++i) { if (getfilecon (data->files [i], &sec_con) == -1) { syslog (LOG_CRIT, "error getting context from file: %s, error %s", data->files [i], strerror (errno)); continue; } con = context_new (sec_con); if (con == NULL) { syslog (LOG_CRIT, "Error creating new context from string: %s", sec_con); ret = -1; goto err_freecon; } if (context_range_set (con, mcs_str) == -1) { syslog (LOG_CRIT, "Error setting context range to %s, " "error: %s", mcs_str, strerror (errno)); ret = -1; goto err_confree; } syslog (LOG_INFO, "Setting context for file %s to %s", data->files [i], context_str (con)); ret = setfilecon (data->files [i], context_str (con)); if (ret != 0) syslog (LOG_CRIT, "setfilecon error:%s", strerror (errno)); context_free (con); freecon (sec_con); } return ret; err_confree: context_free (con); err_freecon: freecon (sec_con); return ret; }
static char * SELinuxGenNewContext(const char *oldcontext, const char *mcs) { char *newcontext = NULL; char *scontext = strdup(oldcontext); context_t con; if (!scontext) goto err; con = context_new(scontext); if (!con) goto err; context_range_set(con, mcs); newcontext = strdup(context_str(con)); context_free(con); err: freecon(scontext); return newcontext; }
int get_default_context_with_rolelevel(const char *user, const char *role, const char *level, security_context_t fromcon, security_context_t * newcon) { int rc = 0; int freefrom = 0; context_t con; char *newfromcon; if (!level) return get_default_context_with_role(user, role, fromcon, newcon); if (!fromcon) { rc = getcon(&fromcon); if (rc < 0) return rc; freefrom = 1; } rc = -1; con = context_new(fromcon); if (!con) goto out; if (context_range_set(con, level)) goto out; newfromcon = context_str(con); if (!newfromcon) goto out; rc = get_default_context_with_role(user, role, newfromcon, newcon); out: context_free(con); if (freefrom) freecon(fromcon); return rc; }
static int mls_range_allowed(pam_handle_t *pamh, security_context_t src, security_context_t dst, int debug) { struct av_decision avd; int retval; unsigned int bit = CONTEXT__CONTAINS; context_t src_context = context_new (src); context_t dst_context = context_new (dst); context_range_set(dst_context, context_range_get(src_context)); if (debug) pam_syslog(pamh, LOG_NOTICE, "Checking if %s mls range valid for %s", dst, context_str(dst_context)); retval = security_compute_av(context_str(dst_context), dst, SECCLASS_CONTEXT, bit, &avd); context_free(src_context); context_free(dst_context); if (retval || ((bit & avd.allowed) != bit)) return 0; return 1; }
/* Basic function to build string representation of context from * user:role:type component and sensitivity:category. * Returned string must be free'd by caller. */ static char* create_context (char *oldcontext, char *mcs) { char *newcontext = NULL, *scontext = NULL; context_t con = { 0, }; scontext = strdup(oldcontext); if (!scontext) return scontext; con = context_new(scontext); if (!con) { perror ("context_new"); return NULL; } context_range_set(con, mcs); newcontext = strdup(context_str(con)); context_free(con); return (newcontext); }
static context_t compute_context_from_mask(security_context_t context, unsigned long opts) { context_t new_context = context_new(context); if (!new_context) return NULL; if ((opts & OPT_CHCON_USER) && context_user_set(new_context, user)) goto error; if ((opts & OPT_CHCON_RANGE) && context_range_set(new_context, range)) goto error; if ((opts & OPT_CHCON_ROLE) && context_role_set(new_context, role)) goto error; if ((opts & OPT_CHCON_TYPE) && context_type_set(new_context, type)) goto error; return new_context; error: context_free (new_context); return NULL; }
context_t FAST_FUNC set_security_context_component(security_context_t cur_context, char *user, char *role, char *type, char *range) { context_t con = context_new(cur_context); if (!con) return NULL; if (user && context_user_set(con, user)) goto error; if (type && context_type_set(con, type)) goto error; if (range && context_range_set(con, range)) goto error; if (role && context_role_set(con, role)) goto error; return con; error: context_free(con); return NULL; }
int get_ordered_context_list_with_level(const char *user, const char *level, security_context_t fromcon, security_context_t ** list) { int rc; int freefrom = 0; context_t con; char *newfromcon; if (!level) return get_ordered_context_list(user, fromcon, list); if (!fromcon) { rc = getcon(&fromcon); if (rc < 0) return rc; freefrom = 1; } rc = -1; con = context_new(fromcon); if (!con) goto out; if (context_range_set(con, level)) goto out; newfromcon = context_str(con); if (!newfromcon) goto out; rc = get_ordered_context_list(user, newfromcon, list); out: context_free(con); if (freefrom) freecon(fromcon); return rc; }
int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char *exec_label, char **label) { int r = -EOPNOTSUPP; #ifdef HAVE_SELINUX _cleanup_freecon_ char *mycon = NULL, *peercon = NULL, *fcon = NULL; _cleanup_context_free_ context_t pcon = NULL, bcon = NULL; security_class_t sclass; const char *range = NULL; assert(socket_fd >= 0); assert(exe); assert(label); if (!mac_selinux_have()) return -EOPNOTSUPP; r = getcon_raw(&mycon); if (r < 0) return -errno; r = getpeercon_raw(socket_fd, &peercon); if (r < 0) return -errno; if (!exec_label) { /* If there is no context set for next exec let's use context of target executable */ r = getfilecon_raw(exe, &fcon); if (r < 0) return -errno; } bcon = context_new(mycon); if (!bcon) return -ENOMEM; pcon = context_new(peercon); if (!pcon) return -ENOMEM; range = context_range_get(pcon); if (!range) return -errno; r = context_range_set(bcon, range); if (r) return -errno; freecon(mycon); mycon = strdup(context_str(bcon)); if (!mycon) return -ENOMEM; sclass = string_to_security_class("process"); r = security_compute_create_raw(mycon, fcon, sclass, label); if (r < 0) return -errno; #endif return r; }
/* * do_set_domain * It tries to replace the domain/range of the current context. */ static int do_set_domain(security_context_t old_context, char *domain, server_rec *s) { security_context_t new_context; security_context_t raw_context; context_t context; char *range; /* * Compute the new security context */ context = context_new(old_context); if (!context) { ap_log_error(APLOG_MARK, APLOG_ERR, errno, s, "SELinux: context_new(\"%s\") failed", old_context); return -1; } range = strchr(domain, ':'); if (range) *range++ = '\0'; if (domain && strcmp(domain, "*") != 0) context_type_set(context, domain); if (range && strcmp(range, "*") != 0) context_range_set(context, range); if (range) *--range = ':'; /* fixup */ new_context = context_str(context); if (!new_context) { ap_log_error(APLOG_MARK, APLOG_ERR, errno, s, "SELinux: context_str(\"%s:%s:%s:%s\") failed", context_user_get(context), context_role_get(context), context_type_get(context), context_range_get(context)); context_free(context); return -1; } /* * If old_context == new_context, we don't need to do anything */ if (selinux_trans_to_raw_context(new_context, &raw_context) < 0) { ap_log_error(APLOG_MARK, APLOG_ERR, errno, s, "SELinux: selinux_trans_to_raw_context(\"%s\") failed", new_context); context_free(context); return -1; } context_free(context); if (!strcmp(old_context, raw_context)) { freecon(raw_context); return 1; } if (setcon_raw(raw_context) < 0) { ap_log_error(APLOG_MARK, APLOG_ERR, errno, s, "SELinux: setcon_raw(\"%s\") failed", raw_context); freecon(raw_context); return -1; } freecon(raw_context); return 0; }
static security_context_t config_context (pam_handle_t *pamh, security_context_t defaultcon, int use_current_range, int debug) { security_context_t newcon=NULL; context_t new_context; int mls_enabled = is_selinux_mls_enabled(); char *response=NULL; char *type=NULL; char resp_val = 0; pam_prompt (pamh, PAM_TEXT_INFO, NULL, _("Default Security Context %s\n"), defaultcon); while (1) { if (query_response(pamh, _("Would you like to enter a different role or level?"), "n", &response, debug) == PAM_SUCCESS) { resp_val = response[0]; _pam_drop(response); } else { resp_val = 'N'; } if ((resp_val == 'y') || (resp_val == 'Y')) { if ((new_context = context_new(defaultcon)) == NULL) goto fail_set; /* Allow the user to enter role and level individually */ if (query_response(pamh, _("role:"), context_role_get(new_context), &response, debug) == PAM_SUCCESS && response[0]) { if (get_default_type(response, &type)) { pam_prompt (pamh, PAM_ERROR_MSG, NULL, _("No default type for role %s\n"), response); _pam_drop(response); continue; } else { if (context_role_set(new_context, response)) goto fail_set; if (context_type_set (new_context, type)) goto fail_set; } } _pam_drop(response); if (mls_enabled) { if (use_current_range) { security_context_t mycon = NULL; context_t my_context; if (getcon(&mycon) != 0) goto fail_set; my_context = context_new(mycon); if (my_context == NULL) { freecon(mycon); goto fail_set; } freecon(mycon); if (context_range_set(new_context, context_range_get(my_context))) { context_free(my_context); goto fail_set; } context_free(my_context); } else if (query_response(pamh, _("level:"), context_range_get(new_context), &response, debug) == PAM_SUCCESS && response[0]) { if (context_range_set(new_context, response)) goto fail_set; } _pam_drop(response); } if (debug) pam_syslog(pamh, LOG_NOTICE, "Selected Security Context %s", context_str(new_context)); /* Get the string value of the context and see if it is valid. */ if (!security_check_context(context_str(new_context))) { newcon = strdup(context_str(new_context)); if (newcon == NULL) goto fail_set; context_free(new_context); /* we have to check that this user is allowed to go into the range they have specified ... role is tied to an seuser, so that'll be checked at setexeccon time */ if (mls_enabled && !mls_range_allowed(pamh, defaultcon, newcon, debug)) { pam_syslog(pamh, LOG_NOTICE, "Security context %s is not allowed for %s", defaultcon, newcon); send_audit_message(pamh, 0, defaultcon, newcon); free(newcon); goto fail_range; } return newcon; } else { send_audit_message(pamh, 0, defaultcon, context_str(new_context)); send_text(pamh,_("Not a valid security context"),debug); } context_free(new_context); /* next time around allocates another */ } else return strdup(defaultcon); } /* end while */ return NULL; fail_set: free(type); _pam_drop(response); context_free (new_context); send_audit_message(pamh, 0, defaultcon, NULL); fail_range: return NULL; }
static security_context_t manual_context (pam_handle_t *pamh, const char *user, int debug) { security_context_t newcon=NULL; context_t new_context; int mls_enabled = is_selinux_mls_enabled(); char *type=NULL; char *response=NULL; while (1) { if (query_response(pamh, _("Would you like to enter a security context? [N] "), NULL, &response, debug) != PAM_SUCCESS) return NULL; if ((response[0] == 'y') || (response[0] == 'Y')) { if (mls_enabled) new_context = context_new ("user:role:type:level"); else new_context = context_new ("user:role:type"); if (!new_context) goto fail_set; if (context_user_set (new_context, user)) goto fail_set; _pam_drop(response); /* Allow the user to enter each field of the context individually */ if (query_response(pamh, _("role:"), NULL, &response, debug) == PAM_SUCCESS && response[0] != '\0') { if (context_role_set (new_context, response)) goto fail_set; if (get_default_type(response, &type)) goto fail_set; if (context_type_set (new_context, type)) goto fail_set; } _pam_drop(response); if (mls_enabled) { if (query_response(pamh, _("level:"), NULL, &response, debug) == PAM_SUCCESS && response[0] != '\0') { if (context_range_set (new_context, response)) goto fail_set; } _pam_drop(response); } /* Get the string value of the context and see if it is valid. */ if (!security_check_context(context_str(new_context))) { newcon = strdup(context_str(new_context)); context_free (new_context); return newcon; } else send_text(pamh,_("Not a valid security context"),debug); context_free (new_context); } else { _pam_drop(response); return NULL; } } /* end while */ fail_set: free(type); _pam_drop(response); context_free (new_context); return NULL; }
static int seapp_context_lookup(enum seapp_kind kind, uid_t uid, int isSystemServer, const char *seinfo, const char *pkgname, const char *path, context_t ctx) { const char *username = NULL; struct seapp_context *cur = NULL; int i; size_t n; uid_t userid; uid_t appid; __selinux_once(once, seapp_context_init); userid = uid / AID_USER; appid = uid % AID_USER; if (appid < AID_APP) { for (n = 0; n < android_id_count; n++) { if (android_ids[n].aid == appid) { username = android_ids[n].name; break; } } if (!username) goto err; } else if (appid < AID_ISOLATED_START) { username = "******"; appid -= AID_APP; } else { username = "******"; appid -= AID_ISOLATED_START; } if (appid >= CAT_MAPPING_MAX_ID || userid >= CAT_MAPPING_MAX_ID) goto err; for (i = 0; i < nspec; i++) { cur = seapp_contexts[i]; if (cur->isSystemServer != isSystemServer) continue; if (cur->user.str) { if (cur->user.is_prefix) { if (strncasecmp(username, cur->user.str, cur->user.len-1)) continue; } else { if (strcasecmp(username, cur->user.str)) continue; } } if (cur->seinfo) { if (!seinfo || strcasecmp(seinfo, cur->seinfo)) continue; } if (cur->name.str) { if(!pkgname) continue; if (cur->name.is_prefix) { if (strncasecmp(pkgname, cur->name.str, cur->name.len-1)) continue; } else { if (strcasecmp(pkgname, cur->name.str)) continue; } } if (cur->path.str) { if (!path) continue; if (cur->path.is_prefix) { if (strncmp(path, cur->path.str, cur->path.len-1)) continue; } else { if (strcmp(path, cur->path.str)) continue; } } if (kind == SEAPP_TYPE && !cur->type) continue; else if (kind == SEAPP_DOMAIN && !cur->domain) continue; if (cur->sebool) { int value = security_get_boolean_active(cur->sebool); if (value == 0) continue; else if (value == -1) { selinux_log(SELINUX_ERROR, \ "Could not find boolean: %s ", cur->sebool); goto err; } } if (kind == SEAPP_TYPE) { if (context_type_set(ctx, cur->type)) goto oom; } else if (kind == SEAPP_DOMAIN) { if (context_type_set(ctx, cur->domain)) goto oom; } if (cur->levelFrom != LEVELFROM_NONE) { char level[255]; switch (cur->levelFrom) { case LEVELFROM_APP: snprintf(level, sizeof level, "s0:c%u,c%u", appid & 0xff, 256 + (appid>>8 & 0xff)); break; case LEVELFROM_USER: snprintf(level, sizeof level, "s0:c%u,c%u", 512 + (userid & 0xff), 768 + (userid>>8 & 0xff)); break; case LEVELFROM_ALL: snprintf(level, sizeof level, "s0:c%u,c%u,c%u,c%u", appid & 0xff, 256 + (appid>>8 & 0xff), 512 + (userid & 0xff), 768 + (userid>>8 & 0xff)); break; default: goto err; } if (context_range_set(ctx, level)) goto oom; } else if (cur->level) {
static security_context_t context_from_env (pam_handle_t *pamh, security_context_t defaultcon, int env_params, int use_current_range, int debug) { security_context_t newcon = NULL; context_t new_context; context_t my_context = NULL; int mls_enabled = is_selinux_mls_enabled(); const char *env = NULL; char *type = NULL; if ((new_context = context_new(defaultcon)) == NULL) goto fail_set; if (env_params && (env = pam_getenv(pamh, "SELINUX_ROLE_REQUESTED")) != NULL && env[0] != '\0') { if (debug) pam_syslog(pamh, LOG_NOTICE, "Requested role: %s", env); if (get_default_type(env, &type)) { pam_syslog(pamh, LOG_NOTICE, "No default type for role %s", env); goto fail_set; } else { if (context_role_set(new_context, env)) goto fail_set; if (context_type_set(new_context, type)) goto fail_set; } } if (mls_enabled) { if ((env = pam_getenv(pamh, "SELINUX_USE_CURRENT_RANGE")) != NULL && env[0] == '1') { if (debug) pam_syslog(pamh, LOG_NOTICE, "SELINUX_USE_CURRENT_RANGE is set"); use_current_range = 1; } if (use_current_range) { security_context_t mycon = NULL; if (getcon(&mycon) != 0) goto fail_set; my_context = context_new(mycon); if (my_context == NULL) { freecon(mycon); goto fail_set; } freecon(mycon); env = context_range_get(my_context); } else { env = pam_getenv(pamh, "SELINUX_LEVEL_REQUESTED"); } if (env != NULL && env[0] != '\0') { if (debug) pam_syslog(pamh, LOG_NOTICE, "Requested level: %s", env); if (context_range_set(new_context, env)) goto fail_set; } } newcon = strdup(context_str(new_context)); if (newcon == NULL) goto fail_set; if (debug) pam_syslog(pamh, LOG_NOTICE, "Selected Security Context %s", newcon); /* Get the string value of the context and see if it is valid. */ if (security_check_context(newcon)) { pam_syslog(pamh, LOG_NOTICE, "Not a valid security context %s", newcon); send_audit_message(pamh, 0, defaultcon, newcon); freecon(newcon); newcon = NULL; goto fail_set; } /* we have to check that this user is allowed to go into the range they have specified ... role is tied to an seuser, so that'll be checked at setexeccon time */ if (mls_enabled && !mls_range_allowed(pamh, defaultcon, newcon, debug)) { pam_syslog(pamh, LOG_NOTICE, "Security context %s is not allowed for %s", defaultcon, newcon); send_audit_message(pamh, 0, defaultcon, newcon); freecon(newcon); newcon = NULL; } fail_set: free(type); context_free(my_context); context_free(new_context); send_audit_message(pamh, 0, defaultcon, NULL); return newcon; }