From patchwork Fri Sep 9 17:44:50 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Roberts, William C" X-Patchwork-Id: 9324049 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 9567060231 for ; Fri, 9 Sep 2016 17:47:33 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 86E1A29F73 for ; Fri, 9 Sep 2016 17:47:33 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 7B0F329F97; Fri, 9 Sep 2016 17:47:33 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.2 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from emsm-gh1-uea11.nsa.gov (smtp.nsa.gov [8.44.101.9]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 0149629F73 for ; Fri, 9 Sep 2016 17:47:31 +0000 (UTC) X-IronPort-AV: E=Sophos;i="5.30,306,1470700800"; d="scan'208";a="19131152" IronPort-PHdr: =?us-ascii?q?9a23=3Aglfo8BDb/kHy9wTD5Eh/UyQJP3N1i/DPJgcQr6Af?= =?us-ascii?q?oPdwSP/4rsbcNUDSrc9gkEXOFd2CrakV0qyI7+u5ADNIoc7Y9itTKNoUD15NoP?= =?us-ascii?q?5VtjRoONSCB0z/IayiRA0BN+MGamVY+WqmO1NeAsf0ag6aiHSz6TkPBke3blIt?= =?us-ascii?q?dazLE4Lfx/66y/q1s8WKJV4Z3XzjPfgrdUr+7V2I8JJH2c06cud54yCKi0MAQ/?= =?us-ascii?q?5Ry2JsKADbtDfHzeD0wqRe9T9Nsekq7c9KXPayVa05SbtFEGZuaDhtt4XWrx2L?= =?us-ascii?q?cS+jrjtZCz1XwVJ0BF3e4RX7WIrhmjfrvep6ni+BNIv5Sq5wES+v5qFnUhjphG?= =?us-ascii?q?IDNiUl2H3Ggcx3yqRAqVSuoAI7i5XYe6mJJfF+eeXbZtpcSm1fGo5TSCdIGJ/m?= =?us-ascii?q?R5ceBOoGe+BDps/yoEVdgwG5AFyzBefryzZNwHSwx6ow3v49CinH2hAtG5QFt3?= =?us-ascii?q?GH/53OKK4OXLXtn+HzxjLZYqYTgG/w?= X-IPAS-Result: =?us-ascii?q?A2EfBAAx9dJX/wHyM5BeGgEBAQECAQEBAQgBAQEBFwEBBAE?= =?us-ascii?q?BCgEBgw4BAQEBAR6BU6YUlConh1JMAQEBAQEBAQECAQJbJ4IyBAMTBYIYAiQTF?= =?us-ascii?q?CAOAwkCFwghCAgDAS0VGAcLBRgEiCnBTwEBASOIMIZgEQGFWx0FiDCGcoo/j0Q?= =?us-ascii?q?CgWyICQyFXZBOVIJuHoFuUAGEWA0XB1qBJwEBAQ?= Received: from unknown (HELO tarius.tycho.ncsc.mil) ([144.51.242.1]) by emsm-gh1-uea11.nsa.gov with ESMTP; 09 Sep 2016 17:47:24 +0000 Received: from prometheus.infosec.tycho.ncsc.mil (prometheus [192.168.25.40]) by tarius.tycho.ncsc.mil (8.14.4/8.14.4) with ESMTP id u89Hl1p2029146; Fri, 9 Sep 2016 13:47:10 -0400 Received: from tarius.tycho.ncsc.mil (tarius.infosec.tycho.ncsc.mil [144.51.242.1]) by prometheus.infosec.tycho.ncsc.mil (8.15.2/8.15.2) with ESMTP id u89HjL31113298 for ; Fri, 9 Sep 2016 13:45:21 -0400 Received: from goalie.tycho.ncsc.mil (goalie [144.51.242.250]) by tarius.tycho.ncsc.mil (8.14.4/8.14.4) with ESMTP id u89HjKVW029002; Fri, 9 Sep 2016 13:45:21 -0400 X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: A1DlAwCA9NJX/yNjr8ZeGgEBAQECAQEBAQgBAQEBgzkBAQEBAR6BU7Y6hBIUhgiBT0wBAgEBAQEBAl6FNlIwgQ8SiErBTgEBCCeIMIlYC4JqHQWIMIZyij+PRAKBbIgVhV2QTlSCbh6BblABhFgrggEBAQE X-IPAS-Result: A1DlAwCA9NJX/yNjr8ZeGgEBAQECAQEBAQgBAQEBgzkBAQEBAR6BU7Y6hBIUhgiBT0wBAgEBAQEBAl6FNlIwgQ8SiErBTgEBCCeIMIlYC4JqHQWIMIZyij+PRAKBbIgVhV2QTlSCbh6BblABhFgrggEBAQE X-IronPort-AV: E=Sophos;i="5.30,306,1470715200"; d="scan'208";a="5696032" Received: from emsm-gh1-uea11.corp.nsa.gov (HELO emsm-gh1-uea11.nsa.gov) ([10.208.41.37]) by goalie.tycho.ncsc.mil with ESMTP; 09 Sep 2016 13:45:19 -0400 IronPort-PHdr: =?us-ascii?q?9a23=3Ak6p2GxMPIOw/8Xba8YAl6mtUPXoX/o7sNwtQ0KIM?= =?us-ascii?q?zox0Kfr/rarrMEGX3/hxlliBBdydsKMdzbSK+Pm5BiRAuc/H6yFaNsQUFlcsso?= =?us-ascii?q?Y/p0QYGsmLCEn2frbBThcRO4B8bmJj5GyxKkNPGczzNBX4q3y26iMOSF2kbVIm?= =?us-ascii?q?btr8FoOatcmrzef6o8SVOFQRwmThKuorc1329VyX7ZhOx9M6a+4Y8VjgmjNwYe?= =?us-ascii?q?NYxGdldxq4vi3XwYOOxqNl6DlaoPk79sRNAu3QdqU8SqFEXnx9azhmrOWijxTI?= =?us-ascii?q?TBOO630ASS1W10MQW0mW2ir9RIv8vhH3vetlgmHaYZW3HvgIXmG54qNqTgL4oD?= =?us-ascii?q?sWPD4+tmfMg4p/i7wf6Amsrhpz2YnVbMSRNeFiVr/MdtMdA2xaV4BeUDIFSpiw?= =?us-ascii?q?dKMTHuEBOqBetIC7qFwQ6VO8GgKlHv+14iNZjX/xm6sh2qIuFh+V8hYnGocRsX?= =?us-ascii?q?DQrdzwcqxUS+e/wbPU1h3Cae9b3XH2742bIVgavfiQUOcoIoLqwk41GlaA0A2d?= X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: =?us-ascii?q?A0EdBAAF9NJX/yNjr8ZeGgEBAQECAQEBA?= =?us-ascii?q?QgBAQEBFgEBAQMBAQEJAQEBgw4BAQEBAR6BU6YUkCaEEhSGCIFPTAEBAQEBAQE?= =?us-ascii?q?BAgECWyeCMgQBFQWCPlIwgQ8SiErBSQEBCAIBJIgwjE0dBYgwhnKKP49EAoFsi?= =?us-ascii?q?BWFXZBOVIJuHoFuUAGEWCtBgUABAQE?= X-IPAS-Result: =?us-ascii?q?A0EdBAAF9NJX/yNjr8ZeGgEBAQECAQEBAQgBAQEBFgEBAQM?= =?us-ascii?q?BAQEJAQEBgw4BAQEBAR6BU6YUkCaEEhSGCIFPTAEBAQEBAQEBAgECWyeCMgQBF?= =?us-ascii?q?QWCPlIwgQ8SiErBSQEBCAIBJIgwjE0dBYgwhnKKP49EAoFsiBWFXZBOVIJuHoF?= =?us-ascii?q?uUAGEWCtBgUABAQE?= X-IronPort-AV: E=Sophos;i="5.30,306,1470700800"; d="scan'208";a="19131048" Received: from fmsmga002-icc.fm.intel.com ([198.175.99.35]) by emsm-gh1-uea11.nsa.gov with ESMTP; 09 Sep 2016 17:45:16 +0000 Received: from fmsmga006-icc.fm.intel.com ([198.175.99.5]) by fmsmga002-icc.fm.intel.com with ESMTP; 09 Sep 2016 10:44:54 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.30,306,1470726000"; d="scan'208";a="6525714" Received: from nuozhang-mobl.amr.corp.intel.com (HELO wcrobert-MOBL1.amr.corp.intel.com) ([10.252.132.242]) by fmsmga006.fm.intel.com with ESMTP; 09 Sep 2016 10:44:52 -0700 From: william.c.roberts@intel.com To: selinux@tycho.nsa.gov, seandroid-list@tycho.nsa.gov, sds@tycho.nsa.gov, jwcart2@tycho.nsa.gov Subject: [PATCH v3] libselinux: clean up process file Date: Fri, 9 Sep 2016 10:44:50 -0700 Message-Id: <1473443090-8776-1-git-send-email-william.c.roberts@intel.com> X-Mailer: git-send-email 1.9.1 X-BeenThere: selinux@tycho.nsa.gov X-Mailman-Version: 2.1.20 Precedence: list List-Id: "Security-Enhanced Linux \(SELinux\) mailing list" List-Post: List-Help: MIME-Version: 1.0 Errors-To: selinux-bounces@tycho.nsa.gov Sender: "Selinux" X-Virus-Scanned: ClamAV using ClamSMTP From: William Roberts The current process_file() code will open the file twice on the case of a binary file, correct this. The general flow through process_file() was a bit difficult to read, streamline the routine to be more readable. Detailed statistics of before and after: Source lines of code reported by cloc on modified files: before: 735 after: 742 Object size difference: before: 195530 bytes after: 195485 bytes Signed-off-by: William Roberts --- libselinux/src/label_file.c | 310 ++++++++++++++++++++++++-------------------- 1 file changed, 166 insertions(+), 144 deletions(-) diff --git a/libselinux/src/label_file.c b/libselinux/src/label_file.c index c89bb35..94b7627 100644 --- a/libselinux/src/label_file.c +++ b/libselinux/src/label_file.c @@ -97,62 +97,40 @@ static int nodups_specs(struct saved_data *data, const char *path) return rc; } -static int load_mmap(struct selabel_handle *rec, const char *path, - struct stat *sb, bool isbinary, - struct selabel_digest *digest) +static int process_text_file(FILE *fp, const char *prefix, struct selabel_handle *rec, const char *path) +{ + int rc; + size_t line_len; + unsigned lineno = 0; + char *line_buf = NULL; + + while (getline(&line_buf, &line_len, fp) > 0) { + rc = process_line(rec, path, prefix, line_buf, ++lineno); + if (rc) + goto out; + } + rc = 0; +out: + free(line_buf); + return rc; +} + +static int load_mmap(FILE *fp, size_t len, struct selabel_handle *rec, const char *path) { struct saved_data *data = (struct saved_data *)rec->data; - char mmap_path[PATH_MAX + 1]; - int mmapfd; int rc; - struct stat mmap_stat; char *addr, *str_buf; - size_t len; int *stem_map; struct mmap_area *mmap_area; uint32_t i, magic, version; uint32_t entry_len, stem_map_len, regex_array_len; - if (isbinary) { - len = strlen(path); - if (len >= sizeof(mmap_path)) - return -1; - strcpy(mmap_path, path); - } else { - rc = snprintf(mmap_path, sizeof(mmap_path), "%s.bin", path); - if (rc >= (int)sizeof(mmap_path)) - return -1; - } - - mmapfd = open(mmap_path, O_RDONLY | O_CLOEXEC); - if (mmapfd < 0) - return -1; - - rc = fstat(mmapfd, &mmap_stat); - if (rc < 0) { - close(mmapfd); - return -1; - } - - /* if mmap is old, ignore it */ - if (mmap_stat.st_mtime < sb->st_mtime) { - close(mmapfd); - return -1; - } - - /* ok, read it in... */ - len = mmap_stat.st_size; - len += (sysconf(_SC_PAGE_SIZE) - 1); - len &= ~(sysconf(_SC_PAGE_SIZE) - 1); - mmap_area = malloc(sizeof(*mmap_area)); if (!mmap_area) { - close(mmapfd); return -1; } - addr = mmap(NULL, len, PROT_READ, MAP_PRIVATE, mmapfd, 0); - close(mmapfd); + addr = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fileno(fp), 0); if (addr == MAP_FAILED) { free(mmap_area); perror("mmap"); @@ -227,7 +205,7 @@ static int load_mmap(struct selabel_handle *rec, const char *path, rc = next_entry(&stem_len, mmap_area, sizeof(uint32_t)); if (rc < 0 || !stem_len) { rc = -1; - goto err; + goto out; } /* Check for stem_len wrap around. */ @@ -236,15 +214,15 @@ static int load_mmap(struct selabel_handle *rec, const char *path, /* Check if over-run before null check. */ rc = next_entry(NULL, mmap_area, (stem_len + 1)); if (rc < 0) - goto err; + goto out; if (buf[stem_len] != '\0') { rc = -1; - goto err; + goto out; } } else { rc = -1; - goto err; + goto out; } /* store the mapping between old and new */ @@ -253,7 +231,7 @@ static int load_mmap(struct selabel_handle *rec, const char *path, newid = store_stem(data, buf, stem_len); if (newid < 0) { rc = newid; - goto err; + goto out; } data->stem_arr[newid].from_mmap = 1; } @@ -264,7 +242,7 @@ static int load_mmap(struct selabel_handle *rec, const char *path, rc = next_entry(®ex_array_len, mmap_area, sizeof(uint32_t)); if (rc < 0 || !regex_array_len) { rc = -1; - goto err; + goto out; } for (i = 0; i < regex_array_len; i++) { @@ -274,7 +252,7 @@ static int load_mmap(struct selabel_handle *rec, const char *path, rc = grow_specs(data); if (rc < 0) - goto err; + goto out; spec = &data->spec_arr[data->nspec]; spec->from_mmap = 1; @@ -284,30 +262,30 @@ static int load_mmap(struct selabel_handle *rec, const char *path, rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t)); if (rc < 0 || !entry_len) { rc = -1; - goto err; + goto out; } str_buf = malloc(entry_len); if (!str_buf) { rc = -1; - goto err; + goto out; } rc = next_entry(str_buf, mmap_area, entry_len); if (rc < 0) - goto err; + goto out; if (str_buf[entry_len - 1] != '\0') { free(str_buf); rc = -1; - goto err; + goto out; } spec->lr.ctx_raw = str_buf; if (strcmp(spec->lr.ctx_raw, "<>") && rec->validating) { if (selabel_validate(rec, &spec->lr) < 0) { selinux_log(SELINUX_ERROR, - "%s: context %s is invalid\n", mmap_path, spec->lr.ctx_raw); - goto err; + "%s: context %s is invalid\n", path, spec->lr.ctx_raw); + goto out; } } @@ -315,17 +293,17 @@ static int load_mmap(struct selabel_handle *rec, const char *path, rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t)); if (rc < 0 || !entry_len) { rc = -1; - goto err; + goto out; } spec->regex_str = (char *)mmap_area->next_addr; rc = next_entry(NULL, mmap_area, entry_len); if (rc < 0) - goto err; + goto out; if (spec->regex_str[entry_len - 1] != '\0') { rc = -1; - goto err; + goto out; } /* Process mode */ @@ -334,14 +312,14 @@ static int load_mmap(struct selabel_handle *rec, const char *path, else rc = next_entry(&mode, mmap_area, sizeof(mode_t)); if (rc < 0) - goto err; + goto out; spec->mode = mode; /* map the stem id from the mmap file to the data->stem_arr */ rc = next_entry(&stem_id, mmap_area, sizeof(int32_t)); if (rc < 0) - goto err; + goto out; if (stem_id < 0 || stem_id >= (int32_t)stem_map_len) spec->stem_id = -1; @@ -351,7 +329,7 @@ static int load_mmap(struct selabel_handle *rec, const char *path, /* retrieve the hasMetaChars bit */ rc = next_entry(&meta_chars, mmap_area, sizeof(uint32_t)); if (rc < 0) - goto err; + goto out; spec->hasMetaChars = meta_chars; /* and prefix length for use by selabel_lookup_best_match */ @@ -359,7 +337,7 @@ static int load_mmap(struct selabel_handle *rec, const char *path, rc = next_entry(&prefix_len, mmap_area, sizeof(uint32_t)); if (rc < 0) - goto err; + goto out; spec->prefix_len = prefix_len; } @@ -368,25 +346,25 @@ static int load_mmap(struct selabel_handle *rec, const char *path, rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t)); if (rc < 0 || !entry_len) { rc = -1; - goto err; + goto out; } spec->regex = (pcre *)mmap_area->next_addr; rc = next_entry(NULL, mmap_area, entry_len); if (rc < 0) - goto err; + goto out; /* Check that regex lengths match. pcre_fullinfo() * also validates its magic number. */ rc = pcre_fullinfo(spec->regex, NULL, PCRE_INFO_SIZE, &len); if (rc < 0 || len != entry_len) { rc = -1; - goto err; + goto out; } rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t)); if (rc < 0 || !entry_len) { rc = -1; - goto err; + goto out; } if (entry_len) { @@ -394,119 +372,163 @@ static int load_mmap(struct selabel_handle *rec, const char *path, spec->lsd.flags |= PCRE_EXTRA_STUDY_DATA; rc = next_entry(NULL, mmap_area, entry_len); if (rc < 0) - goto err; + goto out; /* Check that study data lengths match. */ rc = pcre_fullinfo(spec->regex, &spec->lsd, PCRE_INFO_STUDYSIZE, &len); if (rc < 0 || len != entry_len) { rc = -1; - goto err; + goto out; } } data->nspec++; } - rc = digest_add_specfile(digest, NULL, addr, mmap_stat.st_size, - mmap_path); - if (rc) - goto err; - -err: + rc = 0; +out: free(stem_map); return rc; } -static int process_file(const char *path, const char *suffix, - struct selabel_handle *rec, - const char *prefix, struct selabel_digest *digest) -{ - FILE *fp; +struct file_details { + const char *suffix; struct stat sb; - unsigned int lineno; - size_t line_len = 0; - char *line_buf = NULL; - int rc; - char stack_path[PATH_MAX + 1]; - bool isbinary = false; +}; + +static char *rolling_append(char *current, const char *suffix, size_t max) +{ + size_t size; + size_t suffix_size; + size_t current_size; + + if (!suffix) + return current; + + current_size = strlen(current); + suffix_size = strlen(suffix); + + size = current_size + suffix_size; + if (size < current_size || size < suffix_size) + return NULL; + + /* ensure space for the '.' and the '\0' characters. */ + if (size >= (SIZE_MAX - 2)) + return NULL; + + size += 2; + + if (size > max) + return NULL; + + /* Append any given suffix */ + char *to = current + current_size; + *to++ = '.'; + strcpy(to, suffix); + + return current; +} + +static bool fcontext_is_binary(FILE *fp) +{ uint32_t magic; - /* append the path suffix if we have one */ - if (suffix) { - rc = snprintf(stack_path, sizeof(stack_path), - "%s.%s", path, suffix); - if (rc >= (int)sizeof(stack_path)) { - errno = ENAMETOOLONG; - return -1; - } - path = stack_path; + size_t len = fread(&magic, sizeof(magic), 1, fp); + rewind(fp); + + return (len && (magic == SELINUX_MAGIC_COMPILED_FCONTEXT)); +} + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +static FILE *open_file(const char *path, const char *suffix, + char *save_path, size_t len, struct stat *sb) +{ + unsigned i; + int rc; + char stack_path[len]; + struct file_details *found = NULL; + + /* + * Rolling append of suffix. Try to open with path.suffix then the + * next as path.suffix.suffix and so forth. + */ + struct file_details fdetails[2] = { + { .suffix = suffix }, + { .suffix = "bin" } + }; + + rc = snprintf(stack_path, sizeof(stack_path), "%s", path); + if (rc >= (int) sizeof(stack_path)) { + errno = ENAMETOOLONG; + return NULL; } - /* Open the specification file. */ - fp = fopen(path, "r"); - if (fp) { - __fsetlocking(fp, FSETLOCKING_BYCALLER); + for (i = 0; i < ARRAY_SIZE(fdetails); i++) { - if (fstat(fileno(fp), &sb) < 0) - return -1; - if (!S_ISREG(sb.st_mode)) { - errno = EINVAL; - return -1; - } + /* This handles the case if suffix is null */ + path = rolling_append(stack_path, fdetails[i].suffix, + sizeof(stack_path)); + if (!path) + return NULL; - magic = 0; - if (fread(&magic, sizeof magic, 1, fp) != 1) { - if (ferror(fp)) { - errno = EINVAL; - fclose(fp); - return -1; - } - clearerr(fp); - } + rc = stat(path, &fdetails[i].sb); + if (rc) + continue; - if (magic == SELINUX_MAGIC_COMPILED_FCONTEXT) { - /* file_contexts.bin format */ - fclose(fp); - fp = NULL; - isbinary = true; - } else { - rewind(fp); + /* first file thing found, just take it */ + if (!found) { + strcpy(save_path, path); + found = &fdetails[i]; + continue; } - } else { + /* - * Text file does not exist, so clear the timestamp - * so that we will always pass the timestamp comparison - * with the bin file in load_mmap(). + * Keep picking the newest file found. Where "newest" + * includes equality. This provides a precedence on + * secondary suffixes even when the timestamp is the + * same. Ie choose file_contexts.bin over file_contexts + * even if the time stamp is the same. */ - sb.st_mtime = 0; + if (fdetails[i].sb.st_mtime >= found->sb.st_mtime) { + found = &fdetails[i]; + strcpy(save_path, path); + } } - rc = load_mmap(rec, path, &sb, isbinary, digest); - if (rc == 0) - goto out; + if (!found) { + errno = ENOENT; + return NULL; + } - if (!fp) - return -1; /* no text or bin file */ + memcpy(sb, &found->sb, sizeof(*sb)); + return fopen(save_path, "r"); +} - /* - * Then do detailed validation of the input and fill the spec array - */ - lineno = 0; - rc = 0; - while (getline(&line_buf, &line_len, fp) > 0) { - rc = process_line(rec, path, prefix, line_buf, ++lineno); - if (rc) - goto out; - } +static int process_file(const char *path, const char *suffix, + struct selabel_handle *rec, + const char *prefix, struct selabel_digest *digest) +{ + int rc; + struct stat sb; + FILE *fp = NULL; + char found_path[PATH_MAX]; - rc = digest_add_specfile(digest, fp, NULL, sb.st_size, path); + fp = open_file(path, suffix, found_path, sizeof(found_path), &sb); + if (fp == NULL) + return -1; + rc = fcontext_is_binary(fp) ? + load_mmap(fp, sb.st_size, rec, found_path) : + process_text_file(fp, prefix, rec, found_path); + if (rc < 0) + goto out; + + rc = digest_add_specfile(digest, fp, NULL, sb.st_size, found_path); out: - free(line_buf); - if (fp) - fclose(fp); + fclose(fp); return rc; }