Index: usr.bin/grep/file.c =================================================================== --- usr.bin/grep/file.c +++ usr.bin/grep/file.c @@ -34,9 +34,11 @@ __FBSDID("$FreeBSD$"); #include +#ifndef WITHOUT_CAPSICUM +#include +#endif #include #include -#include #include #include @@ -252,6 +254,9 @@ struct file * grep_open(const char *path) { +#ifndef WITHOUT_CAPSICUM + cap_rights_t ro_rights; +#endif struct file *f; f = grep_malloc(sizeof *f); @@ -262,7 +267,14 @@ f->fd = STDIN_FILENO; } else if ((f->fd = open(path, O_RDONLY)) == -1) goto error1; - +#ifndef WITHOUT_CAPSICUM + if (f->fd != STDIN_FILENO && cap_rights_limit(f->fd, + cap_rights_init(&ro_rights, CAP_FSTAT, CAP_READ)) < 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"); +#endif if (filebehave == FILE_MMAP) { struct stat st; Index: usr.bin/grep/grep.h =================================================================== --- usr.bin/grep/grep.h +++ usr.bin/grep/grep.h @@ -123,6 +123,8 @@ extern const char *color; extern int binbehave, devbehave, dirbehave, filebehave, grepbehave, linkbehave; +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,15 @@ #include __FBSDID("$FreeBSD$"); -#include #include +#ifndef WITHOUT_CAPSICUM +#include +#endif +#include +#ifndef WITHOUT_CAPSICUM +#include +#endif #include #include #include @@ -90,6 +96,9 @@ */ bool matchall; +/* Capsicum */ +bool do_cap_enter = false; + /* Searching patterns */ unsigned int patterns; static unsigned int pattern_sz; @@ -157,6 +166,9 @@ }; static inline const char *init_color(const char *); +#ifndef WITHOUT_CAPSICUM +static int last_included_file(int, char *[]); +#endif /* Housekeeping */ bool file_err; /* file reading error */ @@ -311,6 +323,9 @@ read_patterns(const char *fn) { struct stat st; +#ifndef WITHOUT_CAPSICUM + cap_rights_t ro_rights; +#endif FILE *f; char *line; size_t len; @@ -318,6 +333,11 @@ if ((f = fopen(fn, "r")) == NULL) err(2, "%s", fn); +#ifndef WITHOUT_CAPSICUM + if (cap_rights_limit(fileno(f), cap_rights_init(&ro_rights, CAP_FSTAT, + CAP_READ)) < 0 && errno != ENOSYS) + err(2, "unable to limit rights on: %s", fn); +#endif if ((fstat(fileno(f), &st) == -1) || (S_ISDIR(st.st_mode))) { fclose(f); return; @@ -345,6 +365,30 @@ return (c != NULL && c[0] != '\0' ? c : d); } +#ifndef WITHOUT_CAPSICUM +/* + * 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); +} +#endif + int main(int argc, char *argv[]) { @@ -353,6 +397,9 @@ const char *pn; unsigned long long l; unsigned int aargc, eargc, i; +#ifndef WITHOUT_CAPSICUM + unsigned int largc; +#endif int c, lastc, needpattern, newarg, prevoptind; setlocale(LC_ALL, ""); @@ -360,7 +407,10 @@ #ifndef WITHOUT_NLS catalog = catopen("grep", NL_CAT_LOCALE); #endif - +#ifndef WITHOUT_CAPSICUM + if (caph_limit_stdio() == -1) + err(2, "unable to limit stdio"); +#endif /* 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 +810,41 @@ if ((aargc == 0 || aargc == 1) && !Hflag) hflag = true; - if (aargc == 0 && dirbehave != DIR_RECURSE) + if (aargc == 0 && dirbehave != DIR_RECURSE) { +#ifndef WITHOUT_CAPSICUM + if (cap_enter() < 0 && errno != ENOSYS) + err(2, "unable to enter capability mode"); +#endif 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 + else { +#ifndef WITHOUT_CAPSICUM + largc = last_included_file(aargc, aargv); +#endif for (c = 0; aargc--; ++aargv) { if ((finclude || fexclude) && !file_matching(*aargv)) continue; +#ifndef WITHOUT_CAPSICUM + /* + * Upon the last usable file argument, we enter + * capabilities mode. + */ + if (largc == 0) + do_cap_enter = true; + --largc; +#endif c+= procfile(*aargv); } + } #ifndef WITHOUT_NLS catclose(catalog);