Content-type: text/html
int safe_is_path_trusted(const char *pathname, struct safe_id_range_list *trusted_uids, struct safe_id_range_list *trusted_gids);
safe_is_path_trusted checks if the path name given by pathname can only be modified by the list of trusted users and groups. The type of modifications include the file system object itself, and which file system object the path refers. The results are of this function and safe_is_path_trusted_r(3) are identical. This function does have the limitation that it changes the current working directory during the course of its operation, so it is not thread safe with respect to the shared current working directory. It does have the benefit of better run-time performance, and is able to process path of arbitrary size after expanding symbolic links.
The function returns the type of trust that the path provides based on the trusted users and groups. The specific types of trust for a path are detailed in the return value section.
An error of EINVAL is returned if any of the parameters are NULL.
If a directory entry is not trusted SAFE_PATH_UNTRUSTED is immediately returned. If an error occurs SAFE_PATH_ERROR is returned.
The trust of the entire path is the trust level of the last component of the path if all the prior directory components are trusted and without error.
Relative paths, symbolic links, directories with the sticky bit set and the determination of a path being confidential are described below.
This is done because the process must use a set of paths to arrive at the current working directory. If one of the directories from the current working directory to the root is not trusted, then their is no path the process could use that is trusted to get to the current working directory, so any path relative to the current working directory cannot be trusted.
If the parent directory of a directory entry is sticky dir trusted, and the directory entry type is not a directory, then the path is not trusted. This includes symbolic links and regular files in a sticky dir trusted directory. This is because an untrusted user can create a hard link in the sticky bit directory to make a file appear as if a trusted user created the file.
The constant for each trust level is given with the numeric value given in parenthesis.
This type of directory is safe to use for two types of operations: (1) create a secure directory, or (2) create a temporary file (one that has secure permissions and is only accessed through the file descriptor returned from the create function).
In addition errno can be set to the following errors:
#include "safe_id_range_list.h" #include "safe_is_path_trusted.h" #include <stdio.h> #include <stdlib.h> int main(int argc, char **argv) { char *path; int status; struct safe_id_range_list safe_uids; struct safe_id_range_list safe_gids; if (argc != 2) { fprintf(stderr, "Usage: %s <path>\n", argv[0]); exit(1); } /* init id list structs */ if (safe_init_id_range_list(&safe_uids) == -1) { perror("safe_init_id_range_list(&safe_uids): "); exit(2); } if (safe_init_id_range_list(&safe_gids) == -1) { perror("safe_init_id_range_list(&safe_gids): "); exit(3); } /* add current user's uid and gid to safe lists */ if (safe_add_id_to_list(&safe_uids, getuid()) == -1) { perror("safe_add_id_to_list(&safe_uids, getuid()): "); exit(4); } if (safe_add_id_to_list(&safe_gids, getgid()) == -1) { perror("safe_add_id_to_list(&safe_gids, getgid()): "); exit(5); } path = argv[1]; status = safe_is_path_trusted(path, &safe_uids, &safe_gids); safe_destroy_id_range_list(&safe_uids); safe_destroy_id_range_list(&safe_gids); /* print exact type of trust */ switch (status) { case SAFE_PATH_ERROR: perror("ERROR: safe_is_path_trusted: "); exit(6); case SAFE_PATH_UNTRUSTED: printf("%s is not trusted.\n", path); exit(7); case SAFE_PATH_TRUSTED_STICKY_DIR: printf("%s is a trusted sticky-bit directory.\n", path); break; case SAFE_PATH_TRUSTED: printf("%s is trusted.\n", path); break; case SAFE_PATH_TRUSTED_CONFIDENTIAL: printf("%s is trusted and confidential.\n", path); break; default: printf("ERROR: unknown status: %d\n", status); exit(8); } printf("\nPermissable operations are:\n"); if (status >= SAFE_PATH_TRUSTED_STICKY_DIR) { printf("\n"); printf(" - Create a trusted directory in this directory.\n"); printf("\n"); printf(" - Create a true temporary storage file, using\n"); printf(" mkstemp() followed by unlink() (the path can\n"); printf(" only be used by these two functions).\n"); } if (status >= SAFE_PATH_TRUSTED) { printf("\n"); printf(" - Assume the file can not be modified, or directory\n"); printf(" entries can not be be created by untrusted\n"); printf(" users or groups.\n"); printf("\n"); printf(" - Create files (or non-directory objects) in this\n"); printf(" directory, that can be trusted.\n"); printf("\n"); printf(" - Use the path repeatedly without the possibility\n"); printf(" of an untrusted users or groups creating an\n"); printf(" exploitable race condition.\n"); } if (status >= SAFE_PATH_TRUSTED_CONFIDENTIAL) { printf("\n"); printf(" - Assume the file's contents or directory's entries\n"); printf(" can not be read by untrusted users or groups.\n"); } return 0; }
"How to Open a File and Not Get Hacked", 2008 Third International Conference on Availability, Reliability and Security (ARES)," Barcelona, Spain, March 2008, http://research.cs.wisc.edu/mist/safefile