Index: usr.bin/grep/file.c =================================================================== --- usr.bin/grep/file.c +++ usr.bin/grep/file.c @@ -36,7 +36,6 @@ #include #include #include -#include #include #include @@ -263,6 +262,12 @@ } else if ((f->fd = open(path, O_RDONLY)) == -1) goto error1; + if (f->fd != STDIN_FILENO && cap_rights_limit(f->fd, &ro_rights) < 0 && + errno != ENOSYS) + err(2, "unable to limit rights on: %s", path); + if (do_cap_enter && cap_enter() < 0 && errno != ENOSYS) + err(2, "unable to enter capability mode"); + if (filebehave == FILE_MMAP) { struct stat st; Index: usr.bin/grep/grep.h =================================================================== --- usr.bin/grep/grep.h +++ usr.bin/grep/grep.h @@ -29,6 +29,8 @@ * SUCH DAMAGE. */ +#include + #include #include #include @@ -120,6 +122,9 @@ extern const char *color; extern int binbehave, devbehave, dirbehave, filebehave, grepbehave, linkbehave; +extern cap_rights_t ro_rights; +extern bool do_cap_enter; + extern bool file_err, first, matchall, prev; extern int tail; extern unsigned int dpatterns, fpatterns, patterns; Index: usr.bin/grep/grep.c =================================================================== --- usr.bin/grep/grep.c +++ usr.bin/grep/grep.c @@ -32,9 +32,10 @@ #include __FBSDID("$FreeBSD$"); -#include #include +#include +#include #include #include #include @@ -81,6 +82,10 @@ /* Shortcut for matching all cases like empty regex */ bool matchall; +/* Capsicum */ +cap_rights_t ro_rights; +bool do_cap_enter = false; + /* Searching patterns */ unsigned int patterns; static unsigned int pattern_sz; @@ -145,6 +150,7 @@ }; static inline const char *init_color(const char *); +static int last_included_file(int, char *[]); /* Housekeeping */ bool first = true; /* flag whether we are processing the first match */ @@ -308,6 +314,9 @@ if ((f = fopen(fn, "r")) == NULL) err(2, "%s", fn); + if (cap_rights_limit(fileno(f), &ro_rights) < 0 && + errno != ENOSYS) + err(2, "unable to limit rights on: %s", fn); if ((fstat(fileno(f), &st) == -1) || (S_ISDIR(st.st_mode))) { fclose(f); return; @@ -331,6 +340,27 @@ return (c != NULL && c[0] != '\0' ? c : d); } +/** + * Returns the last argv index used as an input file, or just past the end if none are used + */ +static int +last_included_file(int argc, char *argv[]) +{ + int lastidx = argc, c; + + if (!finclude && !fexclude) + return argc - 1; + + for (c = 0; argc--; ++argv) { + if (!file_matching(*argv)) + continue; + + lastidx = c; + } + + return lastidx; +} + int main(int argc, char *argv[]) { @@ -338,10 +368,11 @@ char *ep; const char *pn; unsigned long long l; - unsigned int aargc, eargc, i; + unsigned int aargc, eargc, i, largc; int c, lastc, needpattern, newarg, prevoptind; setlocale(LC_ALL, ""); + cap_rights_init(&ro_rights, CAP_FSTAT, CAP_READ); #ifndef WITHOUT_NLS catalog = catopen("grep", NL_CAT_LOCALE); @@ -725,17 +756,34 @@ if ((aargc == 0 || aargc == 1) && !Hflag) hflag = true; - if (aargc == 0) + if (caph_limit_stdio() == -1) + err(2, "unable to limit stdio"); + + if (aargc == 0) { + if (cap_enter() < 0 && errno != ENOSYS) + err(2, "unable to enter capability mode"); exit(!procfile("-")); + } + /* + * The recursive case does not currently enter capabilities mode + * at all due to the lack of casper file service. We should revise + * this to encompas all recursive and non-recursive cases later + * when a casper file service or similar approach becomes available. + */ if (dirbehave == DIR_RECURSE) c = grep_tree(aargv); - else - for (c = 0; aargc--; ++aargv) { + else { + largc = last_included_file(aargc, aargv); + for (c = 0; aargc--; ++aargv, --largc) { if ((finclude || fexclude) && !file_matching(*aargv)) continue; + /* Upon the last usable file argument, we enter capabilities mode */ + if (largc == 0) + do_cap_enter = true; c+= procfile(*aargv); } + } #ifndef WITHOUT_NLS catclose(catalog);