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; }
int fgetfilecon(int fd, security_context_t * context) { security_context_t rcontext; int ret; *context = NULL; ret = fgetfilecon_raw(fd, &rcontext); if (ret > 0) { ret = selinux_raw_to_trans_context(rcontext, context); freecon(rcontext); } if (ret >= 0 && *context) return strlen(*context) + 1; return ret; }
int selinux_util_label(const char *path) { int retval = 0; int enforce; struct stat st; security_context_t con; enforce = security_getenforce(); if (retval < 0) return retval; if (!hnd) return (enforce) ? -1 : 0; retval = lstat(path, &st); if (retval < 0) { if (errno == ENOENT) return 0; return (enforce) ? -1 : 0; } /* lookup the context */ retval = selabel_lookup_raw(hnd, &con, path, st.st_mode); if (retval < 0) { if (errno == ENOENT) return 0; return (enforce) ? -1 : 0; } /* apply the context */ retval = lsetfilecon(path, con); freecon(con); if (retval < 0) { if (errno == ENOENT) return 0; if (errno == ENOTSUP) return 0; return (enforce) ? -1 : 0; } return 0; }
static void check_selinux_update_passwd(const char *username) { security_context_t context; char *seuser; if (getuid() != (uid_t)0 || is_selinux_enabled() == 0) return; /* No need to check */ if (getprevcon_raw(&context) < 0) bb_perror_msg_and_die("getprevcon failed"); seuser = strtok(context, ":"); if (!seuser) bb_error_msg_and_die("invalid context '%s'", context); if (strcmp(seuser, username) != 0) { if (checkPasswdAccess(PASSWD__PASSWD) != 0) bb_error_msg_and_die("SELinux: access denied"); } if (ENABLE_FEATURE_CLEAN_UP) freecon(context); }
void setup_selinux_exec_context(char *name) { if (is_selinux_enabled() > 0) { security_context_t user_context=selinux_get_user_context(name); if (setexeccon(user_context)) { if (security_getenforce() > 0) fatal("Failed to set exec security context %s for %s.", user_context, name); else error("Failed to set exec security context %s for %s. " "Continuing in permissive mode", user_context, name); } if (user_context) { freecon(user_context); } } }
int label_fix(const char *path, bool ignore_enoent) { int r = 0; #ifdef HAVE_SELINUX struct stat st; security_context_t fcon; if (!use_selinux() || !label_hnd) return 0; r = lstat(path, &st); if (r == 0) { r = selabel_lookup_raw(label_hnd, &fcon, path, st.st_mode); /* If there's no label to set, then exit without warning */ if (r < 0 && errno == ENOENT) return 0; if (r == 0) { r = setfilecon(path, fcon); freecon(fcon); /* If the FS doesn't support labels, then exit without warning */ if (r < 0 && errno == ENOTSUP) return 0; } } if (r < 0) { /* Ignore ENOENT in some cases */ if (ignore_enoent && errno == ENOENT) return 0; log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG, "Unable to fix label of %s: %m", path); r = security_getenforce() == 1 ? -errno : 0; } #endif return r; }
static char *get_selinux_label(int pid) { #ifdef HAVE_SELINUX_SELINUX_H char *selinux_label; security_context_t pid_context; context_t context; if (getpidcon(pid, &pid_context) == -1) { /* error getting pid selinux context */ dW("Can't get selinux context for process %d\n", pid); return NULL; } context = context_new(pid_context); selinux_label = strdup(context_type_get(context)); context_free(context); freecon(pid_context); return selinux_label; #else return NULL; #endif /* HAVE_SELINUX_SELINUX_H */ }
static int printmatchpathcon(const char *path, int header, int mode) { char *buf; int rc = matchpathcon(path, mode, &buf); if (rc < 0) { if (errno == ENOENT) { buf = strdup("<<none>>"); } else { fprintf(stderr, "matchpathcon(%s) failed: %s\n", path, strerror(errno)); return 1; } } if (header) printf("%s\t%s\n", path, buf); else printf("%s\n", buf); freecon(buf); return 0; }
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; }
static bool check_mac_perms(pid_t spid, uid_t uid, const char *tctx, const char *perm, const char *name) { char *sctx = NULL; const char *class = "service_manager"; bool allowed; struct audit_data ad; if (getpidcon(spid, &sctx) < 0) { ALOGE("SELinux: getpidcon(pid=%d) failed to retrieve pid context.\n", spid); return false; } ad.pid = spid; ad.uid = uid; ad.name = name; int result = selinux_check_access(sctx, tctx, class, perm, (void *) &ad); allowed = (result == 0); freecon(sctx); return allowed; }
/* * selinux_file_context - Set the security context before any file or * directory creation. * * selinux_file_context () should be called before any creation of file, * symlink, directory, ... * * Callers may have to Reset SELinux to create files with default * contexts: * reset_selinux_file_context(); */ int selinux_file_context(const char *dst_name) { security_context_t scontext = NULL; if (is_selinux_enabled() == 1) { /* Get the default security context for this file */ if (matchpathcon(dst_name, 0, &scontext) < 0) { if (security_getenforce () != 0) { return 1; } } /* Set the security context for the next created file */ if (setfscreatecon(scontext) < 0) { if (security_getenforce() != 0) { return 1; } } freecon(scontext); } return 0; }
int make_dir(const char *path, mode_t mode) { int rc; char *secontext = NULL; if (sehandle) { selabel_lookup(sehandle, &secontext, path, mode); setfscreatecon(secontext); } rc = mkdir(path, mode); if (secontext) { int save_errno = errno; freecon(secontext); setfscreatecon(NULL); errno = save_errno; } return rc; }
static void mkswap_selinux_setcontext(int fd, const char *path) { struct stat stbuf; if (!is_selinux_enabled()) return; if (fstat(fd, &stbuf) < 0) bb_perror_msg_and_die("fstat failed"); if (S_ISREG(stbuf.st_mode)) { security_context_t newcon; security_context_t oldcon = NULL; context_t context; if (fgetfilecon(fd, &oldcon) < 0) { if (errno != ENODATA) goto error; if (matchpathcon(path, stbuf.st_mode, &oldcon) < 0) goto error; } context = context_new(oldcon); if (!context || context_type_set(context, "swapfile_t")) goto error; newcon = context_str(context); if (!newcon) goto error; /* fsetfilecon_raw is hidden */ if (strcmp(oldcon, newcon) != 0 && fsetfilecon(fd, newcon) < 0) goto error; if (ENABLE_FEATURE_CLEAN_UP) { context_free(context); freecon(oldcon); } } return; error: bb_perror_msg_and_die("SELinux relabeling failed"); }
static void set_selinux_path_context(const char *matchpath, const char *path, mode_t mode) { #ifdef WITH_SELINUX static int selinux_enabled = -1; security_context_t scontext = NULL; int ret; /* If there's no file type, just give up. */ if ((mode & S_IFMT) == 0) return; /* Set selinux_enabled if it is not already set (singleton). */ if (selinux_enabled < 0) selinux_enabled = (is_selinux_enabled() > 0); /* If SE Linux is not enabled just do nothing. */ if (!selinux_enabled) return; /* XXX: Well, we could use set_matchpathcon_printf() to redirect the * errors from the following bit, but that seems too much effort. */ /* Do nothing if we can't figure out what the context is, or if it has * no context; in which case the default context shall be applied. */ ret = matchpathcon(matchpath, mode & S_IFMT, &scontext); if (ret == -1 || (ret == 0 && scontext == NULL)) return; if (strcmp(scontext, "<<none>>") != 0) { if (lsetfilecon(path, scontext) < 0) /* XXX: This might need to be fatal instead!? */ perror("Error setting security context for next file object:"); } freecon(scontext); #endif /* WITH_SELINUX */ }
static bool check_mac_perms_from_lookup(pid_t spid, uid_t uid, const char *perm, const char *name) { bool allowed; char *tctx = NULL; if (selinux_enabled <= 0) { return true; } if (!sehandle) { ALOGE("SELinux: Failed to find sehandle. Aborting service_manager.\n"); abort(); } if (selabel_lookup(sehandle, &tctx, name, 0) != 0) { ALOGE("SELinux: No match for %s in service_contexts.\n", name); return false; } allowed = check_mac_perms(spid, uid, tctx, perm, name); freecon(tctx); return allowed; }
static int set_context( security_context_t cntx ) { const char *func = "set_context" ; int retval = setexeccon(cntx); if (debug.on) { security_context_t current_exec_context; if ( getexeccon( ¤t_exec_context ) == 0 ) { msg( LOG_DEBUG, func, "current security exec context now: %s", current_exec_context ? current_exec_context : "unknown" ); freecon( current_exec_context ); } else msg( LOG_DEBUG, func, "Error calling getexeccon: %m" ); } return retval; }
static int SELinuxReserveSecurityLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, virDomainDefPtr def, pid_t pid) { security_context_t pctx; context_t ctx = NULL; const char *mcs; if (def->seclabel.type == VIR_DOMAIN_SECLABEL_STATIC) return 0; if (getpidcon(pid, &pctx) == -1) { virReportSystemError(errno, _("unable to get PID %d security context"), pid); return -1; } ctx = context_new(pctx); freecon(pctx); if (!ctx) goto err; mcs = context_range_get(ctx); if (!mcs) goto err; mcsAdd(mcs); context_free(ctx); return 0; err: context_free(ctx); return -1; }
/* Run SHELL, or DEFAULT_SHELL if SHELL is "" or NULL. * If COMMAND is nonzero, pass it to the shell with the -c option. * If ADDITIONAL_ARGS is nonzero, pass it to the shell as more * arguments. */ void FAST_FUNC run_shell(const char *shell, int loginshell, const char *command, const char **additional_args) { const char **args; int argno; int additional_args_cnt = 0; for (args = additional_args; args && *args; args++) additional_args_cnt++; args = xmalloc(sizeof(char*) * (4 + additional_args_cnt)); if (!shell || !shell[0]) shell = DEFAULT_SHELL; args[0] = bb_get_last_path_component_nostrip(shell); if (loginshell) args[0] = xasprintf("-%s", args[0]); argno = 1; if (command) { args[argno++] = "-c"; args[argno++] = command; } if (additional_args) { for (; *additional_args; ++additional_args) args[argno++] = *additional_args; } args[argno] = NULL; #if ENABLE_SELINUX if (current_sid) setexeccon(current_sid); if (ENABLE_FEATURE_CLEAN_UP) freecon(current_sid); #endif execv(shell, (char **) args); bb_perror_msg_and_die("can't execute '%s'", shell); }
static int check_mac_perms(const char *name, char *sctx) { if (is_selinux_enabled() <= 0) return 1; char *tctx = NULL; int result = 0; if (!sctx) goto err; if (!sehandle_prop) goto err; if (selabel_lookup(sehandle_prop, &tctx, name, 1) != 0) goto err; if (selinux_check_access(sctx, tctx, "property_service", "set", (void*) name) == 0) result = 1; freecon(tctx); err: return result; }
/* * Function: getPeerCon * Purpose: retrieves security context of peer socket * Parameters: * fileDescriptor: peer socket file as a FileDescriptor object * Returns: jstring representing the security_context of socket or NULL if error * Exceptions: NullPointerException if fileDescriptor object is NULL */ static jstring getPeerCon(JNIEnv *env, jobject clazz, jobject fileDescriptor) { #ifdef HAVE_SELINUX if (isSELinuxDisabled) return NULL; if (fileDescriptor == NULL) { throw_NullPointerException(env, "Trying to check security context of a null peer socket."); return NULL; } security_context_t context = NULL; jstring securityString = NULL; int fd = jniGetFDFromFileDescriptor(env, fileDescriptor); if (env->ExceptionOccurred() != NULL) { ALOGE("There was an issue with retrieving the file descriptor"); goto bail; } if (getpeercon(fd, &context) == -1) goto bail; ALOGV("getPeerCon: Successfully retrived context of peer socket '%s'", context); securityString = env->NewStringUTF(context); bail: if (context != NULL) freecon(context); return securityString; #else return NULL; #endif }
/* * Function: getCon * Purpose: Get the context of the current process. * Parameters: none * Returns: a jstring representing the security context of the process, * the jstring may be NULL if there was an error * Exceptions: none */ static jstring getCon(JNIEnv *env, jobject clazz) { #ifdef HAVE_SELINUX if (isSELinuxDisabled) return NULL; security_context_t context = NULL; jstring securityString = NULL; if (getcon(&context) == -1) goto bail; ALOGV("getCon: Successfully retrieved context '%s'", context); securityString = env->NewStringUTF(context); bail: if (context != NULL) freecon(context); return securityString; #else return NULL; #endif }
int label_symlinkfile_set(const char *path) { int r = 0; #ifdef HAVE_SELINUX security_context_t filecon = NULL; if (!use_selinux() || !label_hnd) return 0; if ((r = selabel_lookup_raw(label_hnd, &filecon, path, S_IFLNK)) == 0) { if ((r = setfscreatecon(filecon)) < 0) { log_error("Failed to set SELinux file context on %s: %m", path); r = -errno; } freecon(filecon); } if (r < 0 && security_getenforce() == 0) r = 0; #endif return r; }
const char * rpmsxLgetfilecon(rpmsx sx, const char *fn) { const char * scon = NULL; if (sx == NULL) sx = rpmsxI(); if (_rpmsx_debug) fprintf(stderr, "--> %s(%p,%s) sxfn %s\n", __FUNCTION__, sx, fn, sx->fn); #if defined(WITH_SELINUX) if (sx->fn && fn) { security_context_t _con = NULL; int rc = lgetfilecon(fn, &_con); if (rc > 0 && _con != NULL) scon = (const char *) _con; else freecon(_con); } #endif if (_rpmsx_debug) fprintf(stderr, "<-- %s(%p,%s) scon %s\n", __FUNCTION__, sx, fn, scon); return scon; }
static void pw_write(void) { char tmp[FILENAMELEN + 4]; sprintf(tmp, "%s%s", orig_file, ".OLD"); unlink(tmp); if (link(orig_file, tmp)) warn(_("%s: create a link to %s failed"), orig_file, tmp); #ifdef HAVE_LIBSELINUX if (is_selinux_enabled() > 0) { security_context_t passwd_context = NULL; int ret = 0; if (getfilecon(orig_file, &passwd_context) < 0) { warnx(_("Can't get context for %s"), orig_file); pw_error(orig_file, 1, 1); } ret = setfilecon(tmp_file, passwd_context); freecon(passwd_context); if (ret != 0) { warnx(_("Can't set context for %s"), tmp_file); pw_error(tmp_file, 1, 1); } } #endif if (rename(tmp_file, orig_file) == -1) { int errsv = errno; errx(EXIT_FAILURE, ("cannot write %s: %s (your changes are still in %s)"), orig_file, strerror(errsv), tmp_file); } unlink(tmp_file); free(tmp_file); }
/* Return: * -1 error, copy not made * 0 copy is made or user answered "no" in interactive mode * (failures to preserve mode/owner/times are not reported in exit code) */ int FAST_FUNC copy_file(const char *source, const char *dest, int flags) { /* This is a recursive function, try to minimize stack usage */ /* NB: each struct stat is ~100 bytes */ struct stat source_stat; struct stat dest_stat; smallint retval = 0; smallint dest_exists = 0; smallint ovr; /* Inverse of cp -d ("cp without -d") */ #define FLAGS_DEREF (flags & (FILEUTILS_DEREFERENCE + FILEUTILS_DEREFERENCE_L0)) if ((FLAGS_DEREF ? stat : lstat)(source, &source_stat) < 0) { /* This may be a dangling symlink. * Making [sym]links to dangling symlinks works, so... */ if (flags & (FILEUTILS_MAKE_SOFTLINK|FILEUTILS_MAKE_HARDLINK)) goto make_links; bb_perror_msg("can't stat '%s'", source); return -1; } if (lstat(dest, &dest_stat) < 0) { if (errno != ENOENT) { bb_perror_msg("can't stat '%s'", dest); return -1; } } else { if (source_stat.st_dev == dest_stat.st_dev && source_stat.st_ino == dest_stat.st_ino ) { bb_error_msg("'%s' and '%s' are the same file", source, dest); return -1; } dest_exists = 1; } #if ENABLE_SELINUX if ((flags & FILEUTILS_PRESERVE_SECURITY_CONTEXT) && is_selinux_enabled() > 0) { security_context_t con; if (lgetfilecon(source, &con) >= 0) { if (setfscreatecon(con) < 0) { bb_perror_msg("can't set setfscreatecon %s", con); freecon(con); return -1; } } else if (errno == ENOTSUP || errno == ENODATA) { setfscreatecon_or_die(NULL); } else { bb_perror_msg("can't lgetfilecon %s", source); return -1; } } #endif if (S_ISDIR(source_stat.st_mode)) { DIR *dp; const char *tp; struct dirent *d; mode_t saved_umask = 0; if (!(flags & FILEUTILS_RECUR)) { bb_error_msg("omitting directory '%s'", source); return -1; } /* Did we ever create source ourself before? */ tp = is_in_ino_dev_hashtable(&source_stat); if (tp) { /* We did! it's a recursion! man the lifeboats... */ bb_error_msg("recursion detected, omitting directory '%s'", source); return -1; } if (dest_exists) { if (!S_ISDIR(dest_stat.st_mode)) { bb_error_msg("target '%s' is not a directory", dest); return -1; } /* race here: user can substitute a symlink between * this check and actual creation of files inside dest */ } else { /* Create DEST */ mode_t mode; saved_umask = umask(0); mode = source_stat.st_mode; if (!(flags & FILEUTILS_PRESERVE_STATUS)) mode = source_stat.st_mode & ~saved_umask; /* Allow owner to access new dir (at least for now) */ mode |= S_IRWXU; if (mkdir(dest, mode) < 0) { umask(saved_umask); bb_perror_msg("can't create directory '%s'", dest); return -1; } umask(saved_umask); /* need stat info for add_to_ino_dev_hashtable */ if (lstat(dest, &dest_stat) < 0) { bb_perror_msg("can't stat '%s'", dest); return -1; } } /* remember (dev,inode) of each created dir. * NULL: name is not remembered */ add_to_ino_dev_hashtable(&dest_stat, NULL); /* Recursively copy files in SOURCE */ dp = opendir(source); if (dp == NULL) { retval = -1; goto preserve_mode_ugid_time; } while ((d = readdir(dp)) != NULL) { char *new_source, *new_dest; new_source = concat_subpath_file(source, d->d_name); if (new_source == NULL) continue; new_dest = concat_path_file(dest, d->d_name); if (copy_file(new_source, new_dest, flags & ~FILEUTILS_DEREFERENCE_L0) < 0) retval = -1; free(new_source); free(new_dest); } closedir(dp); if (!dest_exists && chmod(dest, source_stat.st_mode & ~saved_umask) < 0 ) { bb_perror_msg("can't preserve %s of '%s'", "permissions", dest); /* retval = -1; - WRONG! copy *WAS* made */ } goto preserve_mode_ugid_time; } if (flags & (FILEUTILS_MAKE_SOFTLINK|FILEUTILS_MAKE_HARDLINK)) { int (*lf)(const char *oldpath, const char *newpath); make_links: /* Hmm... maybe * if (DEREF && MAKE_SOFTLINK) source = realpath(source) ? * (but realpath returns NULL on dangling symlinks...) */ lf = (flags & FILEUTILS_MAKE_SOFTLINK) ? symlink : link; if (lf(source, dest) < 0) { ovr = ask_and_unlink(dest, flags); if (ovr <= 0) return ovr; if (lf(source, dest) < 0) { bb_perror_msg("can't create link '%s'", dest); return -1; } } /* _Not_ jumping to preserve_mode_ugid_time: * (sym)links don't have those */ return 0; } if (/* "cp thing1 thing2" without -R: just open and read() from thing1 */ !(flags & FILEUTILS_RECUR) /* "cp [-opts] regular_file thing2" */ || S_ISREG(source_stat.st_mode) /* DEREF uses stat, which never returns S_ISLNK() == true. * So the below is never true: */ /* || (FLAGS_DEREF && S_ISLNK(source_stat.st_mode)) */ ) { int src_fd; int dst_fd; mode_t new_mode; if (!FLAGS_DEREF && S_ISLNK(source_stat.st_mode)) { /* "cp -d symlink dst": create a link */ goto dont_cat; } if (ENABLE_FEATURE_PRESERVE_HARDLINKS && !FLAGS_DEREF) { const char *link_target; link_target = is_in_ino_dev_hashtable(&source_stat); if (link_target) { if (link(link_target, dest) < 0) { ovr = ask_and_unlink(dest, flags); if (ovr <= 0) return ovr; if (link(link_target, dest) < 0) { bb_perror_msg("can't create link '%s'", dest); return -1; } } return 0; } add_to_ino_dev_hashtable(&source_stat, dest); } src_fd = open_or_warn(source, O_RDONLY); if (src_fd < 0) return -1; /* Do not try to open with weird mode fields */ new_mode = source_stat.st_mode; if (!S_ISREG(source_stat.st_mode)) new_mode = 0666; // POSIX way is a security problem versus (sym)link attacks if (!ENABLE_FEATURE_NON_POSIX_CP) { dst_fd = open(dest, O_WRONLY|O_CREAT|O_TRUNC, new_mode); } else { /* safe way: */ dst_fd = open(dest, O_WRONLY|O_CREAT|O_EXCL, new_mode); } if (dst_fd == -1) { ovr = ask_and_unlink(dest, flags); if (ovr <= 0) { close(src_fd); return ovr; } /* It shouldn't exist. If it exists, do not open (symlink attack?) */ dst_fd = open3_or_warn(dest, O_WRONLY|O_CREAT|O_EXCL, new_mode); if (dst_fd < 0) { close(src_fd); return -1; } } #if ENABLE_SELINUX if ((flags & (FILEUTILS_PRESERVE_SECURITY_CONTEXT|FILEUTILS_SET_SECURITY_CONTEXT)) && is_selinux_enabled() > 0 ) { security_context_t con; if (getfscreatecon(&con) == -1) { bb_perror_msg("getfscreatecon"); return -1; } if (con) { if (setfilecon(dest, con) == -1) { bb_perror_msg("setfilecon:%s,%s", dest, con); freecon(con); return -1; } freecon(con); } } #endif if (bb_copyfd_eof(src_fd, dst_fd) == -1) retval = -1; /* Careful with writing... */ if (close(dst_fd) < 0) { bb_perror_msg("error writing to '%s'", dest); retval = -1; } /* ...but read size is already checked by bb_copyfd_eof */ close(src_fd); /* "cp /dev/something new_file" should not * copy mode of /dev/something */ if (!S_ISREG(source_stat.st_mode)) return retval; goto preserve_mode_ugid_time; } dont_cat: /* Source is a symlink or a special file */ /* We are lazy here, a bit lax with races... */ if (dest_exists) { errno = EEXIST; ovr = ask_and_unlink(dest, flags); if (ovr <= 0) return ovr; } if (S_ISLNK(source_stat.st_mode)) { char *lpath = xmalloc_readlink_or_warn(source); if (lpath) { int r = symlink(lpath, dest); free(lpath); if (r < 0) { bb_perror_msg("can't create symlink '%s'", dest); return -1; } if (flags & FILEUTILS_PRESERVE_STATUS) if (lchown(dest, source_stat.st_uid, source_stat.st_gid) < 0) bb_perror_msg("can't preserve %s of '%s'", "ownership", dest); } /* _Not_ jumping to preserve_mode_ugid_time: * symlinks don't have those */ return 0; } if (S_ISBLK(source_stat.st_mode) || S_ISCHR(source_stat.st_mode) || S_ISSOCK(source_stat.st_mode) || S_ISFIFO(source_stat.st_mode) ) { if (mknod(dest, source_stat.st_mode, source_stat.st_rdev) < 0) { bb_perror_msg("can't create '%s'", dest); return -1; } } else { bb_error_msg("unrecognized file '%s' with mode %x", source, source_stat.st_mode); return -1; } preserve_mode_ugid_time: if (flags & FILEUTILS_PRESERVE_STATUS /* Cannot happen: */ /* && !(flags & (FILEUTILS_MAKE_SOFTLINK|FILEUTILS_MAKE_HARDLINK)) */ ) { struct timeval times[2]; times[1].tv_sec = times[0].tv_sec = source_stat.st_mtime; times[1].tv_usec = times[0].tv_usec = 0; /* BTW, utimes sets usec-precision time - just FYI */ if (utimes(dest, times) < 0) bb_perror_msg("can't preserve %s of '%s'", "times", dest); if (chown(dest, source_stat.st_uid, source_stat.st_gid) < 0) { source_stat.st_mode &= ~(S_ISUID | S_ISGID); bb_perror_msg("can't preserve %s of '%s'", "ownership", dest); } #if ENABLE_XATTR /* Preserve extended attributes. We must copy it after chown() * because it resets capabilities. */ if (copy_file_attr(source, dest) == -1) bb_perror_msg("can't preserve %s of '%s'", "extended attributes", dest); #endif if (chmod(dest, source_stat.st_mode) < 0) bb_perror_msg("can't preserve %s of '%s'", "permissions", dest); } return retval; }
int make_ext4fs_internal(int fd, const char *directory, char *mountpoint, fs_config_func_t fs_config_func, int gzip, int sparse, int crc, int wipe, int init_itabs, struct selabel_handle *sehnd) { u32 root_inode_num; u16 root_mode; if (setjmp(setjmp_env)) return EXIT_FAILURE; /* Handle a call to longjmp() */ if (info.len <= 0) info.len = get_file_size(fd); if (info.len <= 0) { fprintf(stderr, "Need size of filesystem\n"); return EXIT_FAILURE; } if (info.block_size <= 0) info.block_size = compute_block_size(); /* Round down the filesystem length to be a multiple of the block size */ info.len &= ~((u64)info.block_size - 1); if (info.journal_blocks == 0) info.journal_blocks = compute_journal_blocks(); if (info.no_journal == 0) info.feat_compat = EXT4_FEATURE_COMPAT_HAS_JOURNAL; else info.journal_blocks = 0; if (info.blocks_per_group <= 0) info.blocks_per_group = compute_blocks_per_group(); if (info.inodes <= 0) info.inodes = compute_inodes(); if (info.inode_size <= 0) info.inode_size = 256; if (info.label == NULL) info.label = ""; info.inodes_per_group = compute_inodes_per_group(); info.feat_compat |= EXT4_FEATURE_COMPAT_RESIZE_INODE; info.feat_ro_compat |= EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER | EXT4_FEATURE_RO_COMPAT_LARGE_FILE; info.feat_incompat |= EXT4_FEATURE_INCOMPAT_EXTENTS | EXT4_FEATURE_INCOMPAT_FILETYPE; info.bg_desc_reserve_blocks = compute_bg_desc_reserve_blocks(); printf("Creating filesystem with parameters:\n"); printf(" Size: %llu\n", info.len); printf(" Block size: %d\n", info.block_size); printf(" Blocks per group: %d\n", info.blocks_per_group); printf(" Inodes per group: %d\n", info.inodes_per_group); printf(" Inode size: %d\n", info.inode_size); printf(" Journal blocks: %d\n", info.journal_blocks); printf(" Label: %s\n", info.label); ext4_create_fs_aux_info(); printf(" Blocks: %llu\n", aux_info.len_blocks); printf(" Block groups: %d\n", aux_info.groups); printf(" Reserved block group size: %d\n", info.bg_desc_reserve_blocks); info.sparse_file = sparse_file_new(info.block_size, info.len); block_allocator_init(); ext4_fill_in_sb(); MTK_add_mountpoint(aux_info.sb,mountpoint); if (reserve_inodes(0, 10) == EXT4_ALLOCATE_FAILED) error("failed to reserve first 10 inodes"); if (info.feat_compat & EXT4_FEATURE_COMPAT_HAS_JOURNAL) ext4_create_journal_inode(); if (info.feat_compat & EXT4_FEATURE_COMPAT_RESIZE_INODE) ext4_create_resize_inode(); #ifdef USE_MINGW // Windows needs only 'create an empty fs image' functionality assert(!directory); root_inode_num = build_default_directory_structure(); #else if (directory) root_inode_num = build_directory_structure(directory, mountpoint, 0, fs_config_func, sehnd); else root_inode_num = build_default_directory_structure(); #endif root_mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; inode_set_permissions(root_inode_num, root_mode, 0, 0, 0); #ifdef HAVE_SELINUX if (sehnd) { char *sepath = NULL; char *secontext = NULL; if (mountpoint[0] == '/') sepath = strdup(mountpoint); else asprintf(&sepath, "/%s", mountpoint); if (!sepath) critical_error_errno("malloc"); if (selabel_lookup(sehnd, &secontext, sepath, S_IFDIR) < 0) { error("cannot lookup security context for %s", sepath); } if (secontext) { printf("Labeling %s as %s\n", sepath, secontext); inode_set_selinux(root_inode_num, secontext); } free(sepath); freecon(secontext); } #endif ext4_update_free(); if (init_itabs) init_unused_inode_tables(); ext4_queue_sb(); printf("Created filesystem with %d/%d inodes and %d/%d blocks\n", aux_info.sb->s_inodes_count - aux_info.sb->s_free_inodes_count, aux_info.sb->s_inodes_count, aux_info.sb->s_blocks_count_lo - aux_info.sb->s_free_blocks_count_lo, aux_info.sb->s_blocks_count_lo); if (wipe) wipe_block_device(fd, info.len); write_ext4_image(fd, gzip, sparse, crc); sparse_file_destroy(info.sparse_file); info.sparse_file = NULL; return 0; }
int dirCreateHierarchy(const char *path, int mode, const struct utimbuf *timestamp, bool stripFileName, struct selabel_handle *sehnd) { DirStatus ds; /* Check for an empty string before we bother * making any syscalls. */ if (path[0] == '\0') { errno = ENOENT; return -1; } /* Allocate a path that we can modify; stick a slash on * the end to make things easier. */ size_t pathLen = strlen(path); char *cpath = (char *)malloc(pathLen + 2); if (cpath == NULL) { errno = ENOMEM; return -1; } memcpy(cpath, path, pathLen); if (stripFileName) { /* Strip everything after the last slash. */ char *c = cpath + pathLen - 1; while (c != cpath && *c != '/') { c--; } if (c == cpath) { //xxx test this path /* No directory component. Act like the path was empty. */ errno = ENOENT; free(cpath); return -1; } c[1] = '\0'; // Terminate after the slash we found. } else { /* Make sure that the path ends in a slash. */ cpath[pathLen] = '/'; cpath[pathLen + 1] = '\0'; } /* See if it already exists. */ ds = getPathDirStatus(cpath); if (ds == DDIR) { return 0; } else if (ds == DILLEGAL) { return -1; } /* Walk up the path from the root and make each level. * If a directory already exists, no big deal. */ char *p = cpath; while (*p != '\0') { /* Skip any slashes, watching out for the end of the string. */ while (*p != '\0' && *p == '/') { p++; } if (*p == '\0') { break; } /* Find the end of the next path component. * We know that we'll see a slash before the NUL, * because we added it, above. */ while (*p != '/') { p++; } *p = '\0'; /* Check this part of the path and make a new directory * if necessary. */ ds = getPathDirStatus(cpath); if (ds == DILLEGAL) { /* Could happen if some other process/thread is * messing with the filesystem. */ free(cpath); return -1; } else if (ds == DMISSING) { int err; #ifdef HAVE_SELINUX char *secontext = NULL; if (sehnd) { selabel_lookup(sehnd, &secontext, cpath, mode); setfscreatecon(secontext); } #endif err = mkdir(cpath, mode); #ifdef HAVE_SELINUX if (secontext) { freecon(secontext); setfscreatecon(NULL); } #endif if (err != 0) { free(cpath); return -1; } if (timestamp != NULL && utime(cpath, timestamp)) { free(cpath); return -1; } } // else, this directory already exists. /* Repair the path and continue. */ *p = '/'; } free(cpath); return 0; }
void operator()(security_context_t p) const { freecon(p); }
void handle_property_set_fd() { prop_msg msg; int s; int r; int res; struct ucred cr; struct sockaddr_un addr; socklen_t addr_size = sizeof(addr); socklen_t cr_size = sizeof(cr); char * source_ctx = NULL; if ((s = accept(property_set_fd, (struct sockaddr *) &addr, &addr_size)) < 0) { return; } /* Check socket options here */ if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cr_size) < 0) { close(s); ERROR("Unable to receive socket options\n"); return; } r = TEMP_FAILURE_RETRY(recv(s, &msg, sizeof(msg), 0)); if(r != sizeof(prop_msg)) { ERROR("sys_prop: mis-match msg size received: %d expected: %zu errno: %d\n", r, sizeof(prop_msg), errno); close(s); return; } switch(msg.cmd) { case PROP_MSG_SETPROP: msg.name[PROP_NAME_MAX-1] = 0; msg.value[PROP_VALUE_MAX-1] = 0; if (!is_legal_property_name(msg.name, strlen(msg.name))) { ERROR("sys_prop: illegal property name. Got: \"%s\"\n", msg.name); close(s); return; } getpeercon(s, &source_ctx); if(memcmp(msg.name,"ctl.",4) == 0) { // Keep the old close-socket-early behavior when handling // ctl.* properties. close(s); if (check_control_perms(msg.value, cr.uid, cr.gid, source_ctx)) { handle_control_message((char*) msg.name + 4, (char*) msg.value); } else { ERROR("sys_prop: Unable to %s service ctl [%s] uid:%d gid:%d pid:%d\n", msg.name + 4, msg.value, cr.uid, cr.gid, cr.pid); } } else { if (check_perms(msg.name, cr.uid, cr.gid, source_ctx)) { property_set((char*) msg.name, (char*) msg.value); } else { ERROR("sys_prop: permission denied uid:%d name:%s\n", cr.uid, msg.name); } // Note: bionic's property client code assumes that the // property server will not close the socket until *AFTER* // the property is written to memory. close(s); } freecon(source_ctx); break; default: close(s); break; } }
/* appends a file to the tar archive */ int tar_append_file(TAR *t, char *realname, char *savename) { struct stat s; int i; libtar_hashptr_t hp; tar_dev_t *td = NULL; tar_ino_t *ti = NULL; char path[MAXPATHLEN]; #ifdef DEBUG printf("==> tar_append_file(TAR=0x%lx (\"%s\"), realname=\"%s\", " "savename=\"%s\")\n", t, t->pathname, realname, (savename ? savename : "[NULL]")); #endif if (lstat(realname, &s) != 0) { #ifdef DEBUG perror("lstat()"); #endif return -1; } /* set header block */ #ifdef DEBUG puts(" tar_append_file(): setting header block..."); #endif memset(&(t->th_buf), 0, sizeof(struct tar_header)); th_set_from_stat(t, &s); /* set the header path */ #ifdef DEBUG puts(" tar_append_file(): setting header path..."); #endif th_set_path(t, (savename ? savename : realname)); #ifdef HAVE_SELINUX /* get selinux context */ if(t->options & TAR_STORE_SELINUX) { if(t->th_buf.selinux_context != NULL) { free(t->th_buf.selinux_context); t->th_buf.selinux_context = NULL; } security_context_t selinux_context = NULL; if (lgetfilecon(realname, &selinux_context) >= 0) { t->th_buf.selinux_context = strdup(selinux_context); printf("setting selinux context: %s\n", selinux_context); freecon(selinux_context); } else perror("Failed to get selinux context"); } #endif /* check if it's a hardlink */ #ifdef DEBUG puts(" tar_append_file(): checking inode cache for hardlink..."); #endif libtar_hashptr_reset(&hp); if (libtar_hash_getkey(t->h, &hp, &(s.st_dev), (libtar_matchfunc_t)dev_match) != 0) td = (tar_dev_t *)libtar_hashptr_data(&hp); else { #ifdef DEBUG printf("+++ adding hash for device (0x%lx, 0x%lx)...\n", major(s.st_dev), minor(s.st_dev)); #endif td = (tar_dev_t *)calloc(1, sizeof(tar_dev_t)); td->td_dev = s.st_dev; td->td_h = libtar_hash_new(256, (libtar_hashfunc_t)ino_hash); if (td->td_h == NULL) return -1; if (libtar_hash_add(t->h, td) == -1) return -1; } libtar_hashptr_reset(&hp); if (libtar_hash_getkey(td->td_h, &hp, &(s.st_ino), (libtar_matchfunc_t)ino_match) != 0) { ti = (tar_ino_t *)libtar_hashptr_data(&hp); #ifdef DEBUG printf(" tar_append_file(): encoding hard link \"%s\" " "to \"%s\"...\n", realname, ti->ti_name); #endif t->th_buf.typeflag = LNKTYPE; th_set_link(t, ti->ti_name); } else { #ifdef DEBUG printf("+++ adding entry: device (0x%lx,0x%lx), inode %ld " "(\"%s\")...\n", major(s.st_dev), minor(s.st_dev), s.st_ino, realname); #endif ti = (tar_ino_t *)calloc(1, sizeof(tar_ino_t)); if (ti == NULL) return -1; ti->ti_ino = s.st_ino; snprintf(ti->ti_name, sizeof(ti->ti_name), "%s", savename ? savename : realname); libtar_hash_add(td->td_h, ti); } /* check if it's a symlink */ if (TH_ISSYM(t)) { i = readlink(realname, path, sizeof(path)); if (i == -1) return -1; if (i >= MAXPATHLEN) i = MAXPATHLEN - 1; path[i] = '\0'; #ifdef DEBUG printf(" tar_append_file(): encoding symlink \"%s\" -> " "\"%s\"...\n", realname, path); #endif th_set_link(t, path); } /* print file info */ if (t->options & TAR_VERBOSE) th_print_long_ls(t); #ifdef DEBUG puts(" tar_append_file(): writing header"); #endif /* write header */ if (th_write(t) != 0) { #ifdef DEBUG printf("t->fd = %d\n", t->fd); #endif return -1; } #ifdef DEBUG puts(" tar_append_file(): back from th_write()"); #endif /* if it's a regular file, write the contents as well */ if (TH_ISREG(t) && tar_append_regfile(t, realname) != 0) return -1; return 0; }