...
| Code Block | ||||
|---|---|---|---|---|
| ||||
#include <stdlib.h> #include <unistd<limits.h> #include <limits<string.h> #include <libgen.h> #include <unistd.h> #include <sys/stat.h> #include <string<sys/types.h> enum { MAX_SYMLINKS = 5 }; /* Returns nonzero if directory is secure, zero otherwise */ int secure_dir(const char *fullpath) { static unsigned int num_symlinks = 0; char *path_copy = NULL; char **dirs = NULL; int num_of_dirs = 1; int secure = 1; int i, r; struct stat buf; uid_t my_uid = geteuid(); size_t linksize; char* link; if (!(path_copy = strdup(fullpath)))fullpath || fullpath[0] != '/') { /* Handle error */ } /* Figure out how far it is to the root */ for (; ((strcmp(path_copy, "/") != 0) && (strcmp(path_copy, "//") != 0)); path_copy = dirname(path_copy)) { num_of_dirs++; } // now num_of_dirs indicates # of dirs we must check free(path_copy); path_copy = NULL; if (!(dirs = (char **)malloc(num_of_dirs*sizeof(*dirs)))) { /* Handle error */ } if (!(dirs[num_of_dirs - 1] = strdup(fullpath))) { /* Handle error */ } if (!(path_copy = strdup(fullpath))) { if (num_symlinks > MAX_SYMLINKS) { // Could be a symlink loop /* Handle error */ } if (!(path_copy = strdup(fullpath))) { /* Handle error */ } // Figure out how far it is to the root for (; ((strcmp(path_copy, "/") != 0) && (strcmp(path_copy, "//") != 0)); path_copy = dirname(path_copy)) { num_of_dirs++; } // now num_of_dirs indicates # of dirs we must check free(path_copy); path_copy = NULL; if (!(dirs = (char **)malloc(num_of_dirs * sizeof(char *)))) { /* Handle error */ } /* Now fill the dirs array */ forif (i = !(dirs[num_of_dirs - 2; i >= 0; i--) { 1] = strdup(fullpath))) { /* path_copyHandle = dirname(path_copy); error */ } if (!(dirs[i]path_copy = strdup(path_copyfullpath))) { /* handleHandle error */ } } free(path_copy); path_copy = NULL; /* Traverse from the root to the fullpath, * checking permissions along the way */ // Now fill the dirs array for (i = 0; i < num_of_dirs; i++) { - 2; i >= 0; i--) { path_copy = dirname(path_copy); if (!(dirs[i] = strdup(path_copy))) { /* Handle error */ } } free(path_copy); path_copy = NULL; // Traverse from the root to the fullpath, // checking permissions along the way for (i = 0; i < num_of_dirs; i++) { if (lstat(dirs[i], &buf) != 0) { /* Handle error */ } if (S_ISLNK(buf.st_mode)) { // symlink, test linked-to file linksize = buf.st_size + 1; if (lstat(dirs[i], &buf) != 0!(link = (char *)malloc(linksize))) { /* Handle error */ } if (S_ISLNK(buf.st_mode)) { // symlink, test linked-to file r = readlink(dirs[i], link, linksize = buf.st_size+1); if (!(linkr = (char *)malloc(linksize))= -1) { /* Handle error */ } if (readlink( dirs[i], link, linksize) == -1 else if (r >= linksize) { /* Handle truncation error */ } link[linksize-1r] = '\0'; if (!secure_dir(link)) {num_symlinks++; r = secure = 0_dir(link); }num_symlinks--; free(link); link = NULL;if (!r) { break; secure = }0; if (!S_ISDIR( buf.st_mode)) { // not a directory free(link); securelink = 0NULL; break; }break; if ((buf.st_uid != my_uid) && (buf.st_uid != 0)) { } /* Directory is owned by someone besides user or root */ free(link); link = NULL; secure = 0; breakcontinue; } if (i == num_of_dirs - 1!S_ISDIR(buf.st_mode)) { //* leafnot dira */directory secure if (buf.st_mode & (S_IWGRP | S_IWOTH)) { /* dir is writable by others */= 0; break; } if ((buf.st_uid != my_uid) secure && (buf.st_uid != 0;)) { // Directory is break; owned by someone besides user or }root } else {secure /* parent dirs */= 0; if ((buf.st_mode & (S_IWGRP | S_IWOTH)) ||break; } if (buf.st_mode & (S_ISVTXIWGRP | S_IWOTH)) { /*/ dir hasis stickywritable bit off */by others secure = 0; break; } } for (i = 0; i < num_of_dirs; i++) { free(dirs[i]); dirs[i] = NULL; } free(dirs); dirs = NULL; return secure; } |
This compliant solution uses this secure_dir() function to ensure that an attacker may not tamper with the file to be opened and subsequently removed. Note that once the path name of a directory has been checked using secure_dir(), all further file operations on that directory must be performed using the same path.
...