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 @@ -123,6 +125,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, matchall; extern unsigned int dpatterns, fpatterns, patterns; extern struct pat *pattern; 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 @@ -90,6 +91,10 @@ */ bool matchall; +/* Capsicum */ +cap_rights_t ro_rights; +bool do_cap_enter = false; + /* Searching patterns */ unsigned int patterns; static unsigned int pattern_sz; @@ -157,6 +162,7 @@ }; static inline const char *init_color(const char *); +static int last_included_file(int, char *[]); /* Housekeeping */ bool file_err; /* file reading error */ @@ -318,6 +324,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; @@ -345,6 +354,28 @@ 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 as an input file. + */ +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[]) { @@ -352,7 +383,7 @@ 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, ""); @@ -361,6 +392,10 @@ catalog = catopen("grep", NL_CAT_LOCALE); #endif + cap_rights_init(&ro_rights, CAP_FSTAT, CAP_READ); + if (caph_limit_stdio() == -1) + err(2, "unable to limit stdio"); + /* Check what is the program name of the binary. In this way we can have all the funcionalities in one binary without the need of scripting and using ugly hacks. */ @@ -760,17 +795,34 @@ if ((aargc == 0 || aargc == 1) && !Hflag) hflag = true; - if (aargc == 0 && dirbehave != DIR_RECURSE) + if (aargc == 0 && dirbehave != DIR_RECURSE) { + 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);