diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2022-07-29 20:08:41 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2022-07-29 20:08:41 -0700 |
commit | 2f27d6c386daff041017b7aaec51d0e50e603a8e (patch) | |
tree | c78c8777533fbb91bf6aa909eaef1c79b7cfd75e | |
parent | 101303eb8bfd6a5ac99324467e83139e0e6c4b18 (diff) | |
download | safepath-2f27d6c386daff041017b7aaec51d0e50e603a8e.tar.gz safepath-2f27d6c386daff041017b7aaec51d0e50e603a8e.tar.bz2 safepath-2f27d6c386daff041017b7aaec51d0e50e603a8e.zip |
Use regular expression against /proc symlinks.
* safepath.c (bad_proc): New static variable; regular
expression that matches paths under /proc that traverse
dangerous symlinks.
(bad_proc_rx): Compiled version of above regex.
(abs_path_check): Replace ad-hoc path match with regexec call.
(safepath_init, safepath_deinit): New functions needed because
have to compile a regular expression one time, and then
keep using it. We could do this lazily but then we need
pthread_once to make things thread safe.
* safepath.h (safepath_init, safepath_cleanup): Declared.
* testsp.c (main): Call safepath_init and safepath_cleanup.
-rw-r--r-- | safepath.c | 47 | ||||
-rw-r--r-- | safepath.h | 2 | ||||
-rw-r--r-- | testsp.c | 5 |
3 files changed, 43 insertions, 11 deletions
@@ -35,9 +35,19 @@ #include <fcntl.h> #include <pwd.h> #include <grp.h> +#include <regex.h> #include "safepath.h" /* + * Regular expressions used by abs_path_check. + */ + +static const char *bad_proc = { + "^/proc/([0-9]+|self)/(cwd|root|map_files|fd/[0-9]+|task/[0-9]+/(cwd|root|fd/[0-9]+))($|/)" +}; +static regex_t bad_proc_rx; + +/* * Returns non-zero if st informs about an object that is not writable by * anyone other than the real user ID of the process, or else the superuser. */ @@ -200,17 +210,9 @@ static int abs_path_check(const char *abspath) char *sabspath = simplify_path(abspath); if (geteuid() == 0) { - const char *proc = "/proc/"; - size_t proclen = strlen(proc); - - if (strncmp(sabspath, proc, proclen) == 0) { - const char *pid = sabspath + proclen; - size_t pidlen = strspn(pid, "0123456789"); - - if (pid[pidlen] == '/' || pid[pidlen] == 0) { - free(sabspath); - return 0; - } + if (regexec(&bad_proc_rx, sabspath, 0, NULL, 0) == 0) { + free(sabspath); + return 0; } } @@ -268,6 +270,29 @@ static void set_errno(int spres) } } +/* + * Must be called exactly once before safepath_check is used. + * Returns 1 on success, 0 on failure. + */ +int safepath_init(void) +{ + if (regcomp(&bad_proc_rx, bad_proc, REG_EXTENDED | REG_NOSUB) != 0) + return 0; + return 1; +} + +/* + * If safepath_init was was successfully called, this may be called once to + * release the resources allocated by safepath_init. + * The library may not be used after that. + * A new call to safepath_init is permitted after safepath_cleanup. + */ +void safepath_cleanup(void) +{ + regfree(&bad_proc_rx); + memset(&bad_proc_rx, 0, sizeof bad_proc_rx); +} + int safepath_check(const char *name) { struct stat st; @@ -48,6 +48,8 @@ enum { SAFEPATH_TOOLONG, /* component or symlink target too long */ }; +int safepath_init(void); +void safepath_cleanup(void); int safepath_check(const char *name); const char *safepath_strerr(int err); @@ -36,8 +36,13 @@ int main(int argc, char **argv) (void) argc; if (argv[0] && argv[1] && !argv[2]) { + if (!safepath_init()) { + printf("%s: unable to initialize safepath library\n", argv[0]); + return EXIT_FAILURE; + } int res = safepath_check(argv[1]); printf("safepath_check(\"%s\") == %s\n", argv[1], safepath_strerr(res)); + safepath_cleanup(); return res == SAFEPATH_OK ? 0 : EXIT_FAILURE; } else if (argv[0]) { printf("%s: requires exactly one argument\n", argv[0]); |