diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2008-10-21 07:00:00 -0700 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2008-10-21 07:00:00 -0700 |
commit | 7341494707810f709855ea85ce03a8ec3ac8dbaf (patch) | |
tree | 3bfd77f6c3acddfd222b1b0f4cf1a3452bcc1863 /tests/fstest | |
download | extras-7341494707810f709855ea85ce03a8ec3ac8dbaf.tar.gz |
Initial Contributionandroid-1.0release-1.0cdma-import
Diffstat (limited to 'tests/fstest')
-rw-r--r-- | tests/fstest/Android.mk | 43 | ||||
-rw-r--r-- | tests/fstest/README | 68 | ||||
-rw-r--r-- | tests/fstest/perm_checker.c | 399 | ||||
-rw-r--r-- | tests/fstest/perm_checker.conf | 150 |
4 files changed, 660 insertions, 0 deletions
diff --git a/tests/fstest/Android.mk b/tests/fstest/Android.mk new file mode 100644 index 00000000..bf4f17c3 --- /dev/null +++ b/tests/fstest/Android.mk @@ -0,0 +1,43 @@ +# Copyright (C) 2008 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := perm_checker.c + +LOCAL_SHARED_LIBRARIES := libc + +LOCAL_MODULE := perm_checker + +LOCAL_MODULE_TAGS := tests + +include $(BUILD_EXECUTABLE) + +#### + +include $(CLEAR_VARS) + +LOCAL_MODULE := perm_checker.conf + +LOCAL_MODULE_TAGS := tests + +LOCAL_MODULE_CLASS := ETC + +LOCAL_MODULE_PATH := $(TARGET_OUT)/etc/ + +LOCAL_SRC_FILES := $(LOCAL_MODULE) + +include $(BUILD_PREBUILT) diff --git a/tests/fstest/README b/tests/fstest/README new file mode 100644 index 00000000..e4f8194c --- /dev/null +++ b/tests/fstest/README @@ -0,0 +1,68 @@ +All files and directories will be matched against entries taken from +/etc/perm_checker.conf, and any file/directory which fails the ruleset +will cause an error message along with a corresponding explicit (fully +specified and minimal) rule for that file/directory to be printed on +stdout. If only the message "Passed." is printed on stdout, all files are +correctly matched by perm_checker.conf. + +A file or directory will always fail the ruleset unless there is AT LEAST +one matching rule. If there is an explicit (fully specified) <spec> +matching the file or directory name, it will fail if and only if that +explicit <spec> rule fails (i.e., other matching <spec> rules will be +ignored). Otherwise, it will fail if _any_ matching wildcard or recursive +<spec> rule fails to hold. + +Entries in the perm_checker.conf file are of the following form: + +<spec> <min_mode> <max_mode> <min_uid> <max_uid> <min_gid> <max_gid> + +Where <spec> is one of the following: + +A fully specified path name, which must end in / ex: /dev/ +A fully specified filename, symlink, device node, etc. ex: /dev/tty0 + +A recursive path specification, which ends in /... ex: /dev/... +A wildcard file specification, which ends in * ex: /dev/tty* + +By convention /dev/* will include all files directly in /dev/, but not files +that are in subdirectories of /dev/, such as /dev/input/, unlike a +recursive path specification. The wildcard notation * will never result in +a match to a directory name. + +NOTE: Symbolic links are treated specially to prevent infinite recursion +and simplify the ruleset. Symbolic links are ignored unless an explicit +rule with the same name as the symlink exists, in which case the permissions +on the rule must match the permissions on the symlink itself, not the target. + +<min_mode> is a numeric mode mask, and a mode will match it if and only if +(min_mode & mode) == min_mode. + +<max_mode> is a numeric mode mask, and a mode will match it if and only if +(max_mode | mode) == max_mode. + +<min_uid> may be either a numeric user id, or a user name (which must not +start with a number). If it is a user name, getpwnam() will be used to +translate it to a numeric user id. + +<max_uid>, <min_gid>, and <max_gid> have similar syntax to <min_uid>. + + +-- Tips -- + +I recommend to use 19999 as the maximum uid/gid whenever any valid +application uid/gid is acceptable. + +Once the test is installed, it can be executed via: + +adb shell perm_checker + +To get a list of all failing rules: + +adb shell perm_checker | grep "^# INFO #" | sort | uniq + +To get a fully specified set of rules for all failing files: + +adb shell perm_checker | grep -v "^#" + +NOTE: There may be failing files even if no rules have failed, since a +file that does not match any rule is a failure. diff --git a/tests/fstest/perm_checker.c b/tests/fstest/perm_checker.c new file mode 100644 index 00000000..5cead10b --- /dev/null +++ b/tests/fstest/perm_checker.c @@ -0,0 +1,399 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// A simple file permissions checker. See associated README. + +#define _GNU_SOURCE + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <ctype.h> +#include <sys/types.h> +#include <dirent.h> +#include <errno.h> + +#include <sys/stat.h> +#include <unistd.h> +#include <time.h> + +#include <pwd.h> +#include <grp.h> + +#include <linux/kdev_t.h> + +#define PERMS(M) (M & ~S_IFMT) +#define MAX_NAME_LEN 4096 +#define MAX_UID_LEN 256 +#define MAX_GID_LEN MAX_UID_LEN + +enum perm_rule_type {EXACT_FILE = 0, EXACT_DIR, WILDCARD, RECURSIVE, + NUM_PR_TYPES}; + +struct perm_rule { + char *rule_text; + int rule_line; + char *spec; + mode_t min_mode; + mode_t max_mode; + uid_t min_uid; + uid_t max_uid; + gid_t min_gid; + gid_t max_gid; + enum perm_rule_type type; + struct perm_rule *next; +}; + +typedef struct perm_rule perm_rule_t; + +static perm_rule_t *rules[NUM_PR_TYPES]; + +static uid_t str2uid(char *str, int line_num) +{ + struct passwd *pw; + + if (isdigit(str[0])) + return (uid_t) atol(str); + + if (!(pw = getpwnam(str))) { + printf("# ERROR # Invalid uid '%s' reading line %d\n", str, line_num); + exit(255); + } + return pw->pw_uid; +} + +static gid_t str2gid(char *str, int line_num) +{ + struct group *gr; + + if (isdigit(str[0])) + return (uid_t) atol(str); + + if (!(gr = getgrnam(str))) { + printf("# ERROR # Invalid gid '%s' reading line %d\n", str, line_num); + exit(255); + } + return gr->gr_gid; +} + +static int read_rules(FILE *fp) +{ + char spec[MAX_NAME_LEN + 5]; // Allows for "/..." suffix + terminator + char min_uid_buf[MAX_UID_LEN + 1], max_uid_buf[MAX_UID_LEN + 1]; + char min_gid_buf[MAX_GID_LEN + 1], max_gid_buf[MAX_GID_LEN + 1]; + char rule_text_buf[MAX_NAME_LEN + 2*MAX_UID_LEN + 2*MAX_GID_LEN + 9]; + unsigned long min_mode, max_mode; + perm_rule_t *pr; + int res; + int num_rules = 0, num_lines = 0; + + // Note: Use of an unsafe C function here is OK, since this is a test + while ((res = fscanf(fp, "%s %lo %lo %s %s %s %s\n", spec, + &min_mode, &max_mode, min_uid_buf, max_uid_buf, + min_gid_buf, max_gid_buf)) != EOF) { + num_lines++; + if (res < 7) { + printf("# WARNING # Invalid rule on line number %d\n", num_lines); + continue; + } + if (!(pr = malloc(sizeof(perm_rule_t)))) { + printf("Out of memory.\n"); + exit(255); + } + if (snprintf(rule_text_buf, sizeof(rule_text_buf), + "%s %lo %lo %s %s %s %s", spec, min_mode, max_mode, + min_uid_buf, max_uid_buf, min_gid_buf, max_gid_buf) + >= (long int) sizeof(rule_text_buf)) { + // This should never happen, but just in case... + printf("# ERROR # Maximum length limits exceeded on line %d\n", + num_lines); + exit(255); + } + pr->rule_text = strndup(rule_text_buf, sizeof(rule_text_buf)); + pr->rule_line = num_lines; + if (strstr(spec, "/...")) { + pr->spec = strndup(spec, strlen(spec) - 3); + pr->type = RECURSIVE; + } else if (spec[strlen(spec) - 1] == '*') { + pr->spec = strndup(spec, strlen(spec) - 1); + pr->type = WILDCARD; + } else if (spec[strlen(spec) - 1] == '/') { + pr->spec = strdup(spec); + pr->type = EXACT_DIR; + } else { + pr->spec = strdup(spec); + pr->type = EXACT_FILE; + } + if ((pr->spec == NULL) || (pr->rule_text == NULL)) { + printf("Out of memory.\n"); + exit(255); + } + pr->min_mode = min_mode; + pr->max_mode = max_mode; + pr->min_uid = str2uid(min_uid_buf, num_lines); + pr->max_uid = str2uid(max_uid_buf, num_lines); + pr->min_gid = str2gid(min_gid_buf, num_lines); + pr->max_gid = str2gid(max_gid_buf, num_lines); + + // Add the rule to the appropriate set + pr->next = rules[pr->type]; + rules[pr->type] = pr; + num_rules++; +#if 0 // Useful for debugging + printf("rule #%d: type = %d spec = %s min_mode = %o max_mode = %o " + "min_uid = %d max_uid = %d min_gid = %d max_gid = %d\n", + num_rules, pr->type, pr->spec, pr->min_mode, pr->max_mode, + pr->min_uid, pr->max_uid, pr->min_gid, pr->max_gid); +#endif + } + return num_lines - num_rules; +} + +static void print_failed_rule(const perm_rule_t *pr) +{ + printf("# INFO # Failed rule #%d: %s\n", pr->rule_line, pr->rule_text); +} + +static void print_new_rule(const char *name, mode_t mode, uid_t uid, gid_t gid) +{ + struct passwd *pw; + struct group *gr; + gr = getgrgid(gid); + pw = getpwuid(uid); + printf("%s %4o %4o %s %d %s %d\n", name, mode, mode, pw->pw_name, uid, + gr->gr_name, gid); +} + +// Returns 1 if the rule passes, prints the failure and returns 0 if not +static int pass_rule(const perm_rule_t *pr, mode_t mode, uid_t uid, gid_t gid) +{ + if (((pr->min_mode & mode) == pr->min_mode) && + ((pr->max_mode | mode) == pr->max_mode) && + (pr->min_gid <= gid) && (pr->max_gid >= gid) && + (pr->min_uid <= uid) && (pr->max_uid >= uid)) + return 1; + print_failed_rule(pr); + return 0; +} + +// Returns 0 on success +static int validate_file(const char *name, mode_t mode, uid_t uid, gid_t gid) +{ + perm_rule_t *pr; + int rules_matched = 0; + int retval = 0; + + pr = rules[EXACT_FILE]; + while (pr != NULL) { + if (strcmp(name, pr->spec) == 0) { + if (!pass_rule(pr, mode, uid, gid)) + retval++; + else + rules_matched++; // Exact match found + } + pr = pr->next; + } + + if ((retval + rules_matched) > 1) + printf("# WARNING # Multiple exact rules for file: %s\n", name); + + // If any exact rule matched or failed, we are done with this file + if (retval) + print_new_rule(name, mode, uid, gid); + if (rules_matched || retval) + return retval; + + pr = rules[WILDCARD]; + while (pr != NULL) { + // Check if the spec is a prefix of the filename, and that the file + // is actually in the same directory as the wildcard. + if ((strstr(name, pr->spec) == name) && + (!strchr(name + strlen(pr->spec), '/'))) { + if (!pass_rule(pr, mode, uid, gid)) + retval++; + else + rules_matched++; + } + pr = pr->next; + } + + pr = rules[RECURSIVE]; + while (pr != NULL) { + if (strstr(name, pr->spec) == name) { + if (!pass_rule(pr, mode, uid, gid)) + retval++; + else + rules_matched++; + } + pr = pr->next; + } + + if (!rules_matched) + retval++; // In case no rules either matched or failed, be sure to fail + + if (retval) + print_new_rule(name, mode, uid, gid); + + return retval; +} + +// Returns 0 on success +static int validate_link(const char *name, mode_t mode, uid_t uid, gid_t gid) +{ + perm_rule_t *pr; + int rules_matched = 0; + int retval = 0; + + // For now, we match links against "exact" file rules only + pr = rules[EXACT_FILE]; + while (pr != NULL) { + if (strcmp(name, pr->spec) == 0) { + if (!pass_rule(pr, mode, uid, gid)) + retval++; + else + rules_matched++; // Exact match found + } + pr = pr->next; + } + + if ((retval + rules_matched) > 1) + printf("# WARNING # Multiple exact rules for link: %s\n", name); + if (retval) + print_new_rule(name, mode, uid, gid); + + // Note: Unlike files, if no rules matches for links, retval = 0 (success). + return retval; +} + +// Returns 0 on success +static int validate_dir(const char *name, mode_t mode, uid_t uid, gid_t gid) +{ + perm_rule_t *pr; + int rules_matched = 0; + int retval = 0; + + pr = rules[EXACT_DIR]; + while (pr != NULL) { + if (strcmp(name, pr->spec) == 0) { + if (!pass_rule(pr, mode, uid, gid)) + retval++; + else + rules_matched++; // Exact match found + } + pr = pr->next; + } + + if ((retval + rules_matched) > 1) + printf("# WARNING # Multiple exact rules for directory: %s\n", name); + + // If any exact rule matched or failed, we are done with this directory + if (retval) + print_new_rule(name, mode, uid, gid); + if (rules_matched || retval) + return retval; + + pr = rules[RECURSIVE]; + while (pr != NULL) { + if (strstr(name, pr->spec) == name) { + if (!pass_rule(pr, mode, uid, gid)) + retval++; + else + rules_matched++; + } + pr = pr->next; + } + + if (!rules_matched) + retval++; // In case no rules either matched or failed, be sure to fail + + if (retval) + print_new_rule(name, mode, uid, gid); + + return retval; +} + +// Returns 0 on success +static int check_path(const char *name) +{ + char namebuf[MAX_NAME_LEN + 1]; + char tmp[MAX_NAME_LEN + 1]; + DIR *d; + struct dirent *de; + struct stat s; + int err; + int retval = 0; + + err = lstat(name, &s); + if (err < 0) { + if (errno != ENOENT) + { + perror(name); + return 1; + } + return 0; // File doesn't exist anymore + } + + if (S_ISDIR(s.st_mode)) { + if (name[strlen(name) - 1] != '/') + snprintf(namebuf, sizeof(namebuf), "%s/", name); + else + snprintf(namebuf, sizeof(namebuf), "%s", name); + + retval |= validate_dir(namebuf, PERMS(s.st_mode), s.st_uid, s.st_gid); + d = opendir(namebuf); + if(d == 0) { + printf("%s : opendir failed: %s\n", namebuf, strerror(errno)); + return 1; + } + + while ((de = readdir(d)) != 0) { + if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) + continue; + snprintf(tmp, sizeof(tmp), "%s%s", namebuf, de->d_name); + retval |= check_path(tmp); + } + closedir(d); + return retval; + } else if (S_ISLNK(s.st_mode)) { + validate_link(name, PERMS(s.st_mode), s.st_uid, s.st_gid); + } else { + return validate_file(name, PERMS(s.st_mode), s.st_uid, s.st_gid); + } +} + +int main(int argc, char **argv) +{ + FILE *fp; + int i; + + // Initialize ruleset pointers + for (i = 0; i < NUM_PR_TYPES; i++) + rules[i] = NULL; + + if (!(fp = fopen("/etc/perm_checker.conf", "r"))) { + printf("Error opening /etc/perm_checker.conf\n"); + exit(255); + } + read_rules(fp); + fclose(fp); + + if (check_path("/")) + return 255; + + printf("Passed.\n"); + return 0; +} diff --git a/tests/fstest/perm_checker.conf b/tests/fstest/perm_checker.conf new file mode 100644 index 00000000..460f2e4a --- /dev/null +++ b/tests/fstest/perm_checker.conf @@ -0,0 +1,150 @@ +/ 755 755 root root root root +/* 400 755 root root root root +/cache/ 770 770 system system cache cache +/cache/... 770 770 system system cache cache +/cache/lost+found/ 700 770 root root root root +/d/ 755 755 root root root root +/d/... 000 770 root root root root +/data/ 771 771 system system system system +/data/* 000 744 system system system system +/data/anr/ 000 751 root system log log +/data/anr/... 000 662 root system log log +/data/app/ 771 771 system system system system +/data/app/... 644 664 system system system system +/data/dalvik-cache/ 750 751 root root root root +/data/dalvik-cache/... 400 744 root 19999 root 19999 +/data/data 701 771 system system system system +/data/data/... 000 775 system 19999 system 19999 +/data/testinfo/ 770 771 root system root system +/data/testinfo/* 000 664 root system root system +/data/tombstones/ 755 755 system system system system +/data/tombstones/* 000 600 system 19999 system 19999 +/data/lost+found/ 700 770 root root root root +/data/misc/ 1711 1771 root system root misc +/data/misc/akmd_set.txt 600 640 root compass compass compass +/data/misc/rild* 600 660 root radio root radio +/data/misc/hcid/ 770 770 bluetooth bluetooth bluetooth bluetooth +/data/misc/wifi/ 000 1771 system wifi system wifi +/data/misc/wifi/... 000 770 root wifi root wifi +/data/local/ 771 771 shell shell shell shell +/data/local/tmp/ 771 1771 shell shell shell shell +/data/app_private/ 700 771 system system system system +/data/system/... 000 770 system system system system +/dev/ 1777 1777 root root root root +/dev/alarm 660 660 root system root system +/dev/ashmem 666 666 root root root root +/dev/android_adb 600 600 root root root root +/dev/android_ums 640 640 mount mount mount mount +/dev/binder 666 666 root root root root +/dev/console 600 600 root root root root +/dev/full 666 666 root root root root +/dev/hw3d 660 660 system system graphics graphics +/dev/htc-acoustic 600 640 radio radio radio radio +/dev/network_throughput 600 660 root system root system +/dev/network_latency 600 660 root system root system +/dev/cpu_dma_latency 600 660 root system root system +/dev/mem 600 600 root root root root +/dev/msm_mp3 600 660 root system root audio +/dev/msm_pcm_in 660 660 system system audio audio +/dev/msm_pcm_out 660 660 system system audio audio +/dev/msm_perf 600 600 root root root root +/dev/null 666 666 root root root root +/dev/pmem_adsp 660 660 system system audio audio +/dev/pmem 660 660 system system graphics graphics +/dev/ppp 600 600 root root root root +/dev/psaux 600 600 root root root root +/dev/ptmx 666 666 root root root root +/dev/random 666 666 root root root root +/dev/smd0 640 640 radio radio radio radio +/dev/ttyMSM0 600 600 bluetooth bluetooth bluetooth bluetooth +/dev/urandom 666 666 root root root root +/dev/zero 666 666 root root root root +/dev/akm* 640 640 compass compass system system +/dev/km* 600 600 root root root root +/dev/mt9* 600 660 system system system system +/dev/pmem_gpu* 660 660 system system graphics graphics +/dev/qmi* 600 640 radio radio radio radio +/dev/rtc* 600 600 root root root root +/dev/smd* 600 600 root root root root +/dev/tty* 600 600 root root root root +/dev/vc* 600 600 root root root root +/dev/adsp/ 750 755 root root root root +/dev/adsp/* 660 660 system system audio audio +/dev/block/ 750 775 root root root root +/dev/block/* 600 600 root root root root +/dev/graphics/ 755 755 root root root root +/dev/graphics/* 660 660 root root graphics graphics +/dev/input/ 755 755 root root root root +/dev/input/* 660 660 root root input input +/dev/log/ 755 755 root root root root +/dev/log/* 662 662 root root log log +/dev/oncrpc/ 755 755 root root root root +/dev/oncrpc/... 000 660 root camera root camera +/dev/pts/ 755 755 root root root root +/dev/pts/* 600 600 root system root system +/dev/mtd/ 750 775 root root root root +/dev/mtd/* 600 600 root root root root +/dev/socket/ 750 755 root system root system +/dev/socket/dbus 660 660 root bluetooth bluetooth bluetooth +/dev/socket/installd 600 660 system system system system +/dev/socket/mountd 660 660 root mount root mount +/dev/socket/property_service 666 666 root system root system +/dev/socket/rild 660 660 root radio radio radio +/dev/socket/usbd 660 660 root mount mount mount +/dev/socket/zygote 666 666 root root root root +/etc 777 777 root root root root +/proc/ 555 555 root root root root +/proc/... 000 777 root 19999 root 19999 +/proc/sys/kernel/sched_nr_migrate 000 1664 root root root root +/root/ 700 700 root root root root +/sdcard/ 000 077 system system system system +/sdcard/... 000 077 system system system system +/sbin/ 700 770 root root root root +/sbin/... 700 775 root root root root +/sys/ 755 775 root system root system +/sys/... 000 775 root system root system +/sys/android_power/acquire_full_wake_lock 664 664 radio radio system system +/sys/android_power/acquire_partial_wake_lock 664 664 radio radio system system +/sys/android_power/release_wake_lock 664 664 radio radio system system +/sys/android_power/request_state 664 664 radio radio system system +/sys/android_power/state 664 664 radio radio system system +/sys/module/board_trout/parameters/bluetooth_power_on 660 660 root bluetooth bluetooth bluetooth +/sys/qemu_trace/process_name 000 777 root system root system +/sys/qemu_trace/state 000 777 root system root system +/sys/qemu_trace/symbol 000 777 root system root system +/system/ 755 755 root root root root +/system/* 000 664 root system root system +/system/app/ 755 755 root root root root +/system/app/... 600 644 root root root root +/system/bin/... 000 755 root system root system +/system/xbin/... 000 755 root system root system +/system/etc/ 755 755 root root root root +/system/etc/... 000 664 root system root audio +/system/etc/firmware/ 700 755 root root root root +/system/etc/init.goldfish.sh 500 550 root root root root +/system/etc/init.gprs-pppd 500 550 root root root root +/system/etc/init.testmenu 500 550 root root root root +/system/etc/perm_checker.conf 000 777 root system root system +/system/etc/ppp/ 755 775 root system root system +/system/etc/ppp/chap-secrets 600 660 root system root system +/system/etc/ppp/ip-down 500 550 root system root system +/system/etc/ppp/ip-up 500 550 root system root system +/system/etc/security/ 755 755 root root root root +/system/etc/wifi/ 750 755 root system root system +/system/lib/ 755 755 root root root root +/system/lib/... 600 644 root root root root +/system/lib/modules/ 755 755 root root root root +/system/lost+found/ 700 770 root root root root +/system/fonts/ 755 755 root root root root +/system/fonts/... 644 644 root root root root +/system/framework/ 755 755 root root root root +/system/framework/... 600 644 root root root root +/system/media/ 755 755 root root root root +/system/media/... 644 644 root root root root +/system/media/audio/ 755 755 root root root root +/system/media/audio/notifications/ 755 755 root root root root +/system/media/audio/ringtones/ 755 755 root root root root +/system/sounds/ 755 755 root root root root +/system/sounds/... 644 644 root root root root +/system/usr/... 400 755 root root root root +/sqlite_stmt_journals 1777 1777 root root root root |