Added performance tests and creation permission flags
This commit is contained in:
parent
448c862731
commit
467087d76e
@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
#include "process_info.h"
|
#include "process_info.h"
|
||||||
#include "real_filename.h"
|
#include "real_filename.h"
|
||||||
|
#include "set_mode_t.h"
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#define FUSE_USE_VERSION 31
|
#define FUSE_USE_VERSION 31
|
||||||
@ -45,6 +46,10 @@
|
|||||||
#include "temp_permissions_table.h"
|
#include "temp_permissions_table.h"
|
||||||
#include "ui-socket.h"
|
#include "ui-socket.h"
|
||||||
|
|
||||||
|
int auto_create_perm = GRANT_PERM;
|
||||||
|
|
||||||
|
void set_auto_create_perm(int val) { auto_create_perm = val; }
|
||||||
|
|
||||||
static void *xmp_init(struct fuse_conn_info *conn, struct fuse_config *cfg) {
|
static void *xmp_init(struct fuse_conn_info *conn, struct fuse_config *cfg) {
|
||||||
(void)conn;
|
(void)conn;
|
||||||
cfg->use_ino = 1;
|
cfg->use_ino = 1;
|
||||||
@ -85,7 +90,7 @@ static int xmp_getattr(const char *path, struct stat *stbuf,
|
|||||||
else
|
else
|
||||||
res = source_stat(path, stbuf);
|
res = source_stat(path, stbuf);
|
||||||
if (res == -1) {
|
if (res == -1) {
|
||||||
perror("Stat failed");
|
perror("[ICFS] Stat failed");
|
||||||
return -errno;
|
return -errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,7 +154,7 @@ static int xmp_opendir(const char *path, struct fuse_file_info *fi) {
|
|||||||
|
|
||||||
d->dp = source_opendir(path);
|
d->dp = source_opendir(path);
|
||||||
if (d->dp == NULL) {
|
if (d->dp == NULL) {
|
||||||
perror("Opendir failed");
|
perror("[ICFS] Opendir failed");
|
||||||
res = -errno;
|
res = -errno;
|
||||||
free(d);
|
free(d);
|
||||||
return res;
|
return res;
|
||||||
@ -461,7 +466,7 @@ static int xmp_create(const char *path, mode_t mode,
|
|||||||
|
|
||||||
// fprintf(stderr, "%s, %d\n", path, ask_access(path, pi));
|
// fprintf(stderr, "%s, %d\n", path, ask_access(path, pi));
|
||||||
|
|
||||||
if (!interactive_access(path, pi, GRANT_PERM)) {
|
if (!interactive_access(path, pi, auto_create_perm)) {
|
||||||
free(pi.name);
|
free(pi.name);
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
}
|
}
|
||||||
|
@ -14,5 +14,6 @@
|
|||||||
#include <fuse3/fuse.h>
|
#include <fuse3/fuse.h>
|
||||||
|
|
||||||
const struct fuse_operations *get_fuse_operations();
|
const struct fuse_operations *get_fuse_operations();
|
||||||
|
void set_auto_create_perm(int val);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
35
src/main.c
35
src/main.c
@ -10,6 +10,7 @@
|
|||||||
See the file LICENSE.
|
See the file LICENSE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
#define FUSE_USE_VERSION 31
|
#define FUSE_USE_VERSION 31
|
||||||
|
|
||||||
#define _GNU_SOURCE
|
#define _GNU_SOURCE
|
||||||
@ -29,7 +30,26 @@ const char *mountpoint = NULL;
|
|||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
if (argc < 3) {
|
if (argc < 3) {
|
||||||
fprintf(stderr, "Usage: icfs <FUSE arguments> [target directory] [path to "
|
fprintf(stderr, "Usage: icfs <FUSE arguments> [target directory] [path to "
|
||||||
"the permanent permissions database\n");
|
"the permanent permissions database] <ICFS "
|
||||||
|
"arguments>\n\t--no-perm-on-create - do not give permanent "
|
||||||
|
"permissions to files a process creates automatically "
|
||||||
|
"(incompatible with --temp-on-create)\n\t--temp-on-create "
|
||||||
|
"- give temporary permissions to files a process creates "
|
||||||
|
"automatically (incompatible with --no-perm-on-create)\n");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((0 == strcmp(argv[argc - 1], "--no-perm-on-create") &&
|
||||||
|
0 == strcmp(argv[argc - 2], "--temp-on-create")) ||
|
||||||
|
(0 == strcmp(argv[argc - 2], "--no-perm-on-create") &&
|
||||||
|
0 == strcmp(argv[argc - 1], "--temp-on-create"))) {
|
||||||
|
fprintf(stderr, "Usage: icfs <FUSE arguments> [target directory] [path to "
|
||||||
|
"the permanent permissions database] <ICFS "
|
||||||
|
"arguments>\n\t--no-perm-on-create - do not give permanent "
|
||||||
|
"permissions to files a process creates automatically "
|
||||||
|
"(incompatible with --temp-on-create)\n\t--temp-on-create "
|
||||||
|
"- give temporary permissions to files a process creates "
|
||||||
|
"automatically (incompatible with --no-perm-on-create)\n");
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,11 +57,20 @@ int main(int argc, char *argv[]) {
|
|||||||
// permissions than it's caller reqested
|
// permissions than it's caller reqested
|
||||||
umask(0);
|
umask(0);
|
||||||
|
|
||||||
|
if (0 == strcmp(argv[argc - 1], "--no-perm-on-create")) {
|
||||||
|
set_auto_create_perm(0);
|
||||||
|
argc--;
|
||||||
|
}
|
||||||
|
if (0 == strcmp(argv[argc - 1], "--temp-on-create")) {
|
||||||
|
set_auto_create_perm(GRANT_TEMP);
|
||||||
|
argc--;
|
||||||
|
}
|
||||||
|
|
||||||
// ui socket should always be initialized before anything else, since it
|
// ui socket should always be initialized before anything else, since it
|
||||||
// handles the setuid bits!
|
// handles the setuid bits!
|
||||||
int ret = init_ui_socket(argv[argc - 1]);
|
int ret = init_ui_socket(argv[argc - 1]);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
fprintf(stderr, "Could not initalize ui-socket.\n");
|
fprintf(stderr, "[ICFS] Could not initalize ui-socket.\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,7 +78,7 @@ int main(int argc, char *argv[]) {
|
|||||||
|
|
||||||
ret = source_init(mountpoint);
|
ret = source_init(mountpoint);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
perror("source_init");
|
perror("[ICFS] source_init");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@ void set_db_fsuid() {
|
|||||||
|
|
||||||
status = setfsuid(ruid);
|
status = setfsuid(ruid);
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
fprintf(stderr, "Couldn't set uid to %d.\n", ruid);
|
fprintf(stderr, "[ICFS] Couldn't set uid to %d.\n", ruid);
|
||||||
exit(status);
|
exit(status);
|
||||||
}
|
}
|
||||||
pthread_mutex_unlock(&uid_switch);
|
pthread_mutex_unlock(&uid_switch);
|
||||||
@ -56,7 +56,7 @@ void set_real_fsuid() {
|
|||||||
|
|
||||||
status = setfsuid(ruid);
|
status = setfsuid(ruid);
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
fprintf(stderr, "Couldn't set uid to %d.\n", euid);
|
fprintf(stderr, "[ICFS] Couldn't set uid to %d.\n", euid);
|
||||||
exit(status);
|
exit(status);
|
||||||
}
|
}
|
||||||
pthread_mutex_unlock(&uid_switch);
|
pthread_mutex_unlock(&uid_switch);
|
||||||
@ -67,12 +67,13 @@ static int check_table_col_schema(void *notused, int argc, char **argv,
|
|||||||
(void)notused;
|
(void)notused;
|
||||||
(void)colname;
|
(void)colname;
|
||||||
if (argc < 3) {
|
if (argc < 3) {
|
||||||
fprintf(stderr, "Unexpected amount of arguments given to the callback.\n");
|
fprintf(stderr,
|
||||||
|
"[ICFS] Unexpected amount of arguments given to the callback.\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
int column_num = atoi(argv[0]);
|
int column_num = atoi(argv[0]);
|
||||||
if (column_num >= column_count) {
|
if (column_num >= column_count) {
|
||||||
fprintf(stderr, "Table contains unexpected amount of columns.\n");
|
fprintf(stderr, "[ICFS] Table contains unexpected amount of columns.\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,7 +81,8 @@ static int check_table_col_schema(void *notused, int argc, char **argv,
|
|||||||
strcmp(types[column_num], argv[2]) == 0) {
|
strcmp(types[column_num], argv[2]) == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
fprintf(stderr, "Column %d does not conform to the schema.\n", column_num);
|
fprintf(stderr, "[ICFS] Column %d does not conform to the schema.\n",
|
||||||
|
column_num);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,14 +90,15 @@ static int set_flag(void *flag, int argc, char **argv, char **colname) {
|
|||||||
(void)colname;
|
(void)colname;
|
||||||
|
|
||||||
if (argc < 3) {
|
if (argc < 3) {
|
||||||
fprintf(stderr,
|
fprintf(
|
||||||
"Unexpected amount of arguments given to the callback: %d.\n",
|
stderr,
|
||||||
argc);
|
"[ICFS] Unexpected amount of arguments given to the callback: %d.\n",
|
||||||
|
argc);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (atoi(argv[2])) {
|
if (atoi(argv[2])) {
|
||||||
fprintf(stderr, "Third column was: %s\n", argv[2]);
|
fprintf(stderr, "[ICFS] Third column was: %s\n", argv[2]);
|
||||||
*(int *)flag = 1;
|
*(int *)flag = 1;
|
||||||
} else {
|
} else {
|
||||||
*(int *)flag = -1;
|
*(int *)flag = -1;
|
||||||
@ -104,7 +107,7 @@ static int set_flag(void *flag, int argc, char **argv, char **colname) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int create_database_schema() {
|
int create_database_schema() {
|
||||||
fprintf(stderr, "Creating table 'permissions'.\n");
|
fprintf(stderr, "[ICFS] Creating table 'permissions'.\n");
|
||||||
const char *create_query =
|
const char *create_query =
|
||||||
"CREATE TABLE permissions(executable TEXT NOT "
|
"CREATE TABLE permissions(executable TEXT NOT "
|
||||||
"NULL, filename TEXT NOT NULL, mode INTEGER NOT NULL);";
|
"NULL, filename TEXT NOT NULL, mode INTEGER NOT NULL);";
|
||||||
@ -112,12 +115,12 @@ int create_database_schema() {
|
|||||||
int ret = sqlite3_exec(perm_database, create_query, NULL, NULL, &err);
|
int ret = sqlite3_exec(perm_database, create_query, NULL, NULL, &err);
|
||||||
|
|
||||||
if (ret != SQLITE_OK) {
|
if (ret != SQLITE_OK) {
|
||||||
fprintf(stderr, "sqlite3 error: %s\n", err);
|
fprintf(stderr, "[ICFS] sqlite3 error: %s\n", err);
|
||||||
sqlite3_free(err);
|
sqlite3_free(err);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(stderr, "Database created successfully\n");
|
fprintf(stderr, "[ICFS] Database created successfully\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,14 +134,14 @@ int ensure_database_schema() {
|
|||||||
int result = sqlite3_table_column_metadata(
|
int result = sqlite3_table_column_metadata(
|
||||||
perm_database, NULL, table_name, NULL, NULL, NULL, NULL, NULL, NULL);
|
perm_database, NULL, table_name, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||||
if (result == SQLITE_ERROR) {
|
if (result == SQLITE_ERROR) {
|
||||||
fprintf(stderr, "Table '%s' does not exist.\n", table_name);
|
fprintf(stderr, "[ICFS] Table '%s' does not exist.\n", table_name);
|
||||||
if (create_database_schema()) {
|
if (create_database_schema()) {
|
||||||
fprintf(stderr, "Table could not be created.\n");
|
fprintf(stderr, "[ICFS] Table could not be created.\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
} else if (result != SQLITE_OK) {
|
} else if (result != SQLITE_OK) {
|
||||||
fprintf(stderr, "Database metadata could not be retrieved.\n");
|
fprintf(stderr, "[ICFS] Database metadata could not be retrieved.\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,12 +151,12 @@ int ensure_database_schema() {
|
|||||||
sqlite3_exec(perm_database, pragma, check_table_col_schema, NULL, &err);
|
sqlite3_exec(perm_database, pragma, check_table_col_schema, NULL, &err);
|
||||||
|
|
||||||
if (ret != SQLITE_OK) {
|
if (ret != SQLITE_OK) {
|
||||||
fprintf(stderr, "sqlite3 error: %s\n", err);
|
fprintf(stderr, "[ICFS] sqlite3 error: %s\n", err);
|
||||||
sqlite3_free(err);
|
sqlite3_free(err);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(stderr, "Schema is correct.\n");
|
fprintf(stderr, "[ICFS] Schema is correct.\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -168,24 +171,25 @@ int init_perm_permissions_table(const char *db_filename) {
|
|||||||
umask(0077);
|
umask(0077);
|
||||||
ruid = getuid();
|
ruid = getuid();
|
||||||
euid = geteuid();
|
euid = geteuid();
|
||||||
fprintf(stderr, "Running with uid: %d, gid: %d\n", euid, getegid());
|
fprintf(stderr, "[ICFS] Running with uid: %d, gid: %d\n", euid, getegid());
|
||||||
|
|
||||||
if (sqlite3_open_v2(db_filename, &perm_database,
|
if (sqlite3_open_v2(db_filename, &perm_database,
|
||||||
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE |
|
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE |
|
||||||
SQLITE_OPEN_FULLMUTEX,
|
SQLITE_OPEN_FULLMUTEX,
|
||||||
NULL)) {
|
NULL)) {
|
||||||
perror("Can't open permanent permissions database");
|
perror("[ICFS] Can't open permanent permissions database");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
umask(0);
|
umask(0);
|
||||||
if (ensure_database_schema()) {
|
if (ensure_database_schema()) {
|
||||||
fprintf(stderr, "Database schema is not correct.\n");
|
fprintf(stderr, "[ICFS] Database schema is not correct.\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int status = seteuid(ruid);
|
int status = seteuid(ruid);
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
fprintf(stderr, "Couldn't set euid to ruid during database setup.\n");
|
fprintf(stderr,
|
||||||
|
"[ICFS] Couldn't set euid to ruid during database setup.\n");
|
||||||
exit(status);
|
exit(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -222,7 +226,7 @@ access_t check_perm_access_noparent(const char *filename,
|
|||||||
|
|
||||||
int step_ret = sqlite3_step(stmt);
|
int step_ret = sqlite3_step(stmt);
|
||||||
if (step_ret != SQLITE_ROW && step_ret != SQLITE_DONE) {
|
if (step_ret != SQLITE_ROW && step_ret != SQLITE_DONE) {
|
||||||
fprintf(stderr, "SQLite error: %s\n", sqlite3_errstr(step_ret));
|
fprintf(stderr, "[ICFS] SQLite error: %s\n", sqlite3_errstr(step_ret));
|
||||||
sqlite3_finalize(stmt);
|
sqlite3_finalize(stmt);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -304,7 +308,7 @@ int set_perm_access(const char *filename, struct process_info pi,
|
|||||||
// asprintf). That does not explicitly rule out that query will be a valid
|
// asprintf). That does not explicitly rule out that query will be a valid
|
||||||
// pointer. But the risk of freeing a non-allocated pointer is too much to
|
// pointer. But the risk of freeing a non-allocated pointer is too much to
|
||||||
// justify preparing for this.
|
// justify preparing for this.
|
||||||
fprintf(stderr, "Could not create query on rule insertion\n");
|
fprintf(stderr, "[ICFS] Could not create query on rule insertion\n");
|
||||||
perror("");
|
perror("");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -313,7 +317,7 @@ int set_perm_access(const char *filename, struct process_info pi,
|
|||||||
ret = sqlite3_exec(perm_database, query, NULL, NULL, &sqlite_error);
|
ret = sqlite3_exec(perm_database, query, NULL, NULL, &sqlite_error);
|
||||||
free(query);
|
free(query);
|
||||||
if (ret != SQLITE_OK) {
|
if (ret != SQLITE_OK) {
|
||||||
fprintf(stderr, "SQLite returned an error: %s\n", sqlite_error);
|
fprintf(stderr, "[ICFS] SQLite returned an error: %s\n", sqlite_error);
|
||||||
sqlite3_free(sqlite_error);
|
sqlite3_free(sqlite_error);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,8 @@ pid_t get_main_thread_pid(pid_t tid) {
|
|||||||
|
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
if (tgid != tid) {
|
if (tgid != tid) {
|
||||||
fprintf(stderr, "The tid and and pid wasn't equal. tid:%d, pid:%d.\n", tid,
|
fprintf(stderr,
|
||||||
|
"[ICFS] The tid and and pid wasn't equal. tid:%d, pid:%d.\n", tid,
|
||||||
tgid);
|
tgid);
|
||||||
}
|
}
|
||||||
return tgid;
|
return tgid;
|
||||||
@ -59,7 +60,7 @@ char *get_process_name_by_pid(const int pid) {
|
|||||||
size_t size = 128;
|
size_t size = 128;
|
||||||
char *name = malloc(size);
|
char *name = malloc(size);
|
||||||
if (name == NULL) {
|
if (name == NULL) {
|
||||||
fprintf(stderr, "Could not get process name by pid %d", pid);
|
fprintf(stderr, "[ICFS] Could not get process name by pid %d", pid);
|
||||||
perror("");
|
perror("");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -68,7 +69,7 @@ char *get_process_name_by_pid(const int pid) {
|
|||||||
ssize_t len = readlink(path, name, size);
|
ssize_t len = readlink(path, name, size);
|
||||||
|
|
||||||
if (len == -1) {
|
if (len == -1) {
|
||||||
fprintf(stderr, "Could not get process name by pid %d", pid);
|
fprintf(stderr, "[ICFS] Could not get process name by pid %d", pid);
|
||||||
perror("");
|
perror("");
|
||||||
free(name);
|
free(name);
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -105,7 +106,7 @@ pid_t get_parent_pid(pid_t pid) {
|
|||||||
|
|
||||||
FILE *file = fopen(path, "r");
|
FILE *file = fopen(path, "r");
|
||||||
if (file == NULL) {
|
if (file == NULL) {
|
||||||
perror("Failed to open /proc/<pid>/status");
|
perror("[ICFS] Failed to open /proc/<pid>/status");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ const char *source_filename_translate(const char *filename) {
|
|||||||
int source_init(const char *root_path) {
|
int source_init(const char *root_path) {
|
||||||
handle.mountpoint = malloc(strlen(root_path) + 1);
|
handle.mountpoint = malloc(strlen(root_path) + 1);
|
||||||
if (handle.mountpoint == NULL) {
|
if (handle.mountpoint == NULL) {
|
||||||
perror("Malloc failed");
|
perror("[ICFS] Malloc failed");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,7 +41,8 @@ int source_init(const char *root_path) {
|
|||||||
int root_fd = open(root_path, O_PATH);
|
int root_fd = open(root_path, O_PATH);
|
||||||
|
|
||||||
if (root_fd == -1) {
|
if (root_fd == -1) {
|
||||||
fprintf(stderr, "Could not initialize source file system at %s", root_path);
|
fprintf(stderr, "[ICFS] Could not initialize source file system at %s",
|
||||||
|
root_path);
|
||||||
perror("");
|
perror("");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -65,7 +66,7 @@ const char *real_filename(const char *filename) {
|
|||||||
// Allocate memory (+1 for null terminator)
|
// Allocate memory (+1 for null terminator)
|
||||||
char *result = malloc(total_len + 1);
|
char *result = malloc(total_len + 1);
|
||||||
if (result == NULL) {
|
if (result == NULL) {
|
||||||
fprintf(stderr, "Memory allocation failed");
|
fprintf(stderr, "[ICFS] Memory allocation failed");
|
||||||
perror("");
|
perror("");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -111,7 +112,7 @@ DIR *source_opendir(const char *filename) {
|
|||||||
const char *relative_filename = source_filename_translate(filename);
|
const char *relative_filename = source_filename_translate(filename);
|
||||||
int fd = openat(handle.root_fd, relative_filename, 0);
|
int fd = openat(handle.root_fd, relative_filename, 0);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
perror("Openat failed");
|
perror("[ICFS] Openat failed");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
DIR *dir_pointer = fdopendir(fd);
|
DIR *dir_pointer = fdopendir(fd);
|
||||||
@ -148,7 +149,7 @@ int source_truncate(const char *filename, off_t length) {
|
|||||||
const char *relative_filename = source_filename_translate(filename);
|
const char *relative_filename = source_filename_translate(filename);
|
||||||
int fd = openat(handle.root_fd, relative_filename, 0);
|
int fd = openat(handle.root_fd, relative_filename, 0);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
perror("Openat failed");
|
perror("[ICFS] Openat failed");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return ftruncate(fd, length);
|
return ftruncate(fd, length);
|
||||||
|
@ -52,20 +52,21 @@ unsigned long long get_process_creation_time(pid_t pid) {
|
|||||||
// Open the status file
|
// Open the status file
|
||||||
fp = fopen(path, "r");
|
fp = fopen(path, "r");
|
||||||
if (fp == NULL) {
|
if (fp == NULL) {
|
||||||
perror("fopen");
|
perror("[ICFS] fopen");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the creation time (the 22nd field in the stat file)
|
// Read the creation time (the 22nd field in the stat file)
|
||||||
for (int i = 1; i < 22; i++) {
|
for (int i = 1; i < 22; i++) {
|
||||||
if (fscanf(fp, "%*s") == EOF) {
|
if (fscanf(fp, "%*s") == EOF) {
|
||||||
fprintf(stderr, "Error reading process stat file on the number %d\n", i);
|
fprintf(stderr,
|
||||||
|
"[ICFS] Error reading process stat file on the number %d\n", i);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (fscanf(fp, "%llu", &creation_time) != 1) {
|
if (fscanf(fp, "%llu", &creation_time) != 1) {
|
||||||
fprintf(stderr, "Error reading creation time\n");
|
fprintf(stderr, "[ICFS] Error reading creation time\n");
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -183,7 +184,7 @@ access_t check_temp_access_noparent(const char *filename, pid_t pid) {
|
|||||||
if (permission_entry != NULL) {
|
if (permission_entry != NULL) {
|
||||||
unsigned long long process_creation_time = get_process_creation_time(pid);
|
unsigned long long process_creation_time = get_process_creation_time(pid);
|
||||||
if (process_creation_time == 0) {
|
if (process_creation_time == 0) {
|
||||||
perror("Could not retrieve process creation time");
|
perror("[ICFS] Could not retrieve process creation time");
|
||||||
pthread_rwlock_unlock(&temp_permissions_table_lock);
|
pthread_rwlock_unlock(&temp_permissions_table_lock);
|
||||||
return NDEF;
|
return NDEF;
|
||||||
}
|
}
|
||||||
@ -271,7 +272,7 @@ int set_temp_access(const char *filename, struct process_info pi,
|
|||||||
unsigned long long process_creation_time =
|
unsigned long long process_creation_time =
|
||||||
get_process_creation_time(pi.PID);
|
get_process_creation_time(pi.PID);
|
||||||
if (process_creation_time == 0) {
|
if (process_creation_time == 0) {
|
||||||
perror("Could not retrieve process creation time");
|
perror("[ICFS] Could not retrieve process creation time");
|
||||||
pthread_rwlock_unlock(&temp_permissions_table_lock);
|
pthread_rwlock_unlock(&temp_permissions_table_lock);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -45,19 +45,21 @@ int init_ui_socket(const char *perm_permissions_db_filename) {
|
|||||||
access_log = fopen("/etc/icfs-log", "a+");
|
access_log = fopen("/etc/icfs-log", "a+");
|
||||||
|
|
||||||
if (init_temp_permissions_table()) {
|
if (init_temp_permissions_table()) {
|
||||||
fprintf(stderr, "Could not initialize temporary permissions table.\n");
|
fprintf(stderr,
|
||||||
|
"[ICFS] Could not initialize temporary permissions table.\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (init_perm_permissions_table(perm_permissions_db_filename)) {
|
if (init_perm_permissions_table(perm_permissions_db_filename)) {
|
||||||
fprintf(stderr, "Could not initialize permanent permissions table.\n");
|
fprintf(stderr,
|
||||||
|
"[ICFS] Could not initialize permanent permissions table.\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test if dialogue is installed (get version)
|
// Test if dialogue is installed (get version)
|
||||||
fp = popen("icfs_dialogue --version", "r");
|
fp = popen("icfs_dialogue --version", "r");
|
||||||
if (fp == NULL) {
|
if (fp == NULL) {
|
||||||
perror("Pipe returned an error");
|
perror("[ICFS] Pipe returned an error");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,7 +98,7 @@ struct dialogue_response ask_access(const char *filename,
|
|||||||
// asprintf). That does not explicitly rule out that command will be a valid
|
// asprintf). That does not explicitly rule out that command will be a valid
|
||||||
// pointer. But the risk of freeing a non-allocated pointer is too much to
|
// pointer. But the risk of freeing a non-allocated pointer is too much to
|
||||||
// justify preparing for this.
|
// justify preparing for this.
|
||||||
fprintf(stderr, "Could not create query on rule insertion");
|
fprintf(stderr, "[ICFS] Could not create query on rule insertion");
|
||||||
perror("");
|
perror("");
|
||||||
response.decision = DENY;
|
response.decision = DENY;
|
||||||
response.filename = malloc(2);
|
response.filename = malloc(2);
|
||||||
@ -110,7 +112,7 @@ struct dialogue_response ask_access(const char *filename,
|
|||||||
free(command);
|
free(command);
|
||||||
|
|
||||||
if (fp == NULL) {
|
if (fp == NULL) {
|
||||||
perror("Pipe returned a error");
|
perror("[ICFS] Pipe returned a error");
|
||||||
response.decision = DENY;
|
response.decision = DENY;
|
||||||
response.filename = malloc(2);
|
response.filename = malloc(2);
|
||||||
response.filename[0] = '/';
|
response.filename[0] = '/';
|
||||||
@ -130,8 +132,8 @@ struct dialogue_response ask_access(const char *filename,
|
|||||||
|
|
||||||
int dialogue_exit_code = WEXITSTATUS(pclose(fp));
|
int dialogue_exit_code = WEXITSTATUS(pclose(fp));
|
||||||
|
|
||||||
fprintf(stderr, "dialogue wrote out %s\n", first(&dialogue_output));
|
fprintf(stderr, "[ICFS] dialogue wrote out %s\n", first(&dialogue_output));
|
||||||
fprintf(stderr, "dialogue returned %d\n", dialogue_exit_code);
|
fprintf(stderr, "[ICFS] dialogue returned %d\n", dialogue_exit_code);
|
||||||
|
|
||||||
if (size(&dialogue_output) == 0) {
|
if (size(&dialogue_output) == 0) {
|
||||||
push(&dialogue_output, '/');
|
push(&dialogue_output, '/');
|
||||||
@ -146,7 +148,7 @@ struct dialogue_response ask_access(const char *filename,
|
|||||||
// assert(0 == strcmp(response.filename, first(&dialogue_output)));
|
// assert(0 == strcmp(response.filename, first(&dialogue_output)));
|
||||||
cleanup(&dialogue_output);
|
cleanup(&dialogue_output);
|
||||||
time_t now = time(0);
|
time_t now = time(0);
|
||||||
fprintf(access_log, "%ld\n", now);
|
fprintf(access_log, "[ICFS] wrote to access log: %ld\n", now);
|
||||||
|
|
||||||
if (dialogue_exit_code == (DIALOGUE_YES | DIALOGUE_PERM)) {
|
if (dialogue_exit_code == (DIALOGUE_YES | DIALOGUE_PERM)) {
|
||||||
response.decision = ALLOW;
|
response.decision = ALLOW;
|
||||||
@ -179,19 +181,21 @@ int interactive_access(const char *filename, struct process_info proc_info,
|
|||||||
|
|
||||||
access_t access = check_temp_access(real_path, proc_info);
|
access_t access = check_temp_access(real_path, proc_info);
|
||||||
if (access == ALLOW) {
|
if (access == ALLOW) {
|
||||||
fprintf(stderr,
|
fprintf(
|
||||||
"Permission allowed to %s based on a rule present in the temp "
|
stderr,
|
||||||
"permission table.\n",
|
"[ICFS] Permission allowed to %s based on a rule present in the temp "
|
||||||
proc_info.name);
|
"permission table.\n",
|
||||||
|
proc_info.name);
|
||||||
free(real_path);
|
free(real_path);
|
||||||
pthread_mutex_unlock(&access_check_mutex);
|
pthread_mutex_unlock(&access_check_mutex);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (access == DENY) {
|
if (access == DENY) {
|
||||||
fprintf(stderr,
|
fprintf(
|
||||||
"Permission denied to %s based on a rule present in the temp "
|
stderr,
|
||||||
"permission table.\n",
|
"[ICFS] Permission denied to %s based on a rule present in the temp "
|
||||||
proc_info.name);
|
"permission table.\n",
|
||||||
|
proc_info.name);
|
||||||
free(real_path);
|
free(real_path);
|
||||||
pthread_mutex_unlock(&access_check_mutex);
|
pthread_mutex_unlock(&access_check_mutex);
|
||||||
return 0;
|
return 0;
|
||||||
@ -199,19 +203,21 @@ int interactive_access(const char *filename, struct process_info proc_info,
|
|||||||
|
|
||||||
access = check_perm_access(real_path, proc_info);
|
access = check_perm_access(real_path, proc_info);
|
||||||
if (access == ALLOW) {
|
if (access == ALLOW) {
|
||||||
fprintf(stderr,
|
fprintf(
|
||||||
"Permission allowed to %s based on a rule present in the perm "
|
stderr,
|
||||||
"permission table.\n",
|
"[ICFS] Permission allowed to %s based on a rule present in the perm "
|
||||||
proc_info.name);
|
"permission table.\n",
|
||||||
|
proc_info.name);
|
||||||
free(real_path);
|
free(real_path);
|
||||||
pthread_mutex_unlock(&access_check_mutex);
|
pthread_mutex_unlock(&access_check_mutex);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (access == DENY) {
|
if (access == DENY) {
|
||||||
fprintf(stderr,
|
fprintf(
|
||||||
"Permission denied to %s based on a rule present in the perm "
|
stderr,
|
||||||
"permission table.\n",
|
"[ICFS] Permission denied to %s based on a rule present in the perm "
|
||||||
proc_info.name);
|
"permission table.\n",
|
||||||
|
proc_info.name);
|
||||||
free(real_path);
|
free(real_path);
|
||||||
pthread_mutex_unlock(&access_check_mutex);
|
pthread_mutex_unlock(&access_check_mutex);
|
||||||
return 0;
|
return 0;
|
||||||
@ -221,14 +227,16 @@ int interactive_access(const char *filename, struct process_info proc_info,
|
|||||||
// permissions are granted
|
// permissions are granted
|
||||||
|
|
||||||
if (opts & GRANT_PERM) {
|
if (opts & GRANT_PERM) {
|
||||||
fprintf(stderr, "Permission granted permanently to %s.\n", proc_info.name);
|
fprintf(stderr, "[ICFS] Permission granted permanently to %s.\n",
|
||||||
|
proc_info.name);
|
||||||
set_perm_access(real_path, proc_info, SET_ALLOW);
|
set_perm_access(real_path, proc_info, SET_ALLOW);
|
||||||
free(real_path);
|
free(real_path);
|
||||||
pthread_mutex_unlock(&access_check_mutex);
|
pthread_mutex_unlock(&access_check_mutex);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (opts & GRANT_TEMP) {
|
if (opts & GRANT_TEMP) {
|
||||||
fprintf(stderr, "Permission granted temporarily to %s.\n", proc_info.name);
|
fprintf(stderr, "[ICFS] Permission granted temporarily to %s.\n",
|
||||||
|
proc_info.name);
|
||||||
set_temp_access(real_path, proc_info, SET_ALLOW);
|
set_temp_access(real_path, proc_info, SET_ALLOW);
|
||||||
free(real_path);
|
free(real_path);
|
||||||
pthread_mutex_unlock(&access_check_mutex);
|
pthread_mutex_unlock(&access_check_mutex);
|
||||||
@ -244,7 +252,7 @@ int interactive_access(const char *filename, struct process_info proc_info,
|
|||||||
|
|
||||||
while (source_access(response.filename, F_OK)) {
|
while (source_access(response.filename, F_OK)) {
|
||||||
// if it is invalid, just ask again.
|
// if it is invalid, just ask again.
|
||||||
fprintf(stderr, "Filename returned by zenty wasn't correct: %s\n",
|
fprintf(stderr, "[ICFS] Filename returned by zenty wasn't correct: %s\n",
|
||||||
response.filename);
|
response.filename);
|
||||||
free(response.filename);
|
free(response.filename);
|
||||||
response = ask_access(filename, proc_info);
|
response = ask_access(filename, proc_info);
|
||||||
@ -259,26 +267,30 @@ int interactive_access(const char *filename, struct process_info proc_info,
|
|||||||
|
|
||||||
if (response.decision == ALLOW) {
|
if (response.decision == ALLOW) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"Permission granted permanently to %s based on zenty response.\n",
|
"[ICFS] Permission granted permanently to %s based on zenty "
|
||||||
|
"response.\n",
|
||||||
proc_info.name);
|
proc_info.name);
|
||||||
set_perm_access(real_path, proc_info, SET_ALLOW);
|
set_perm_access(real_path, proc_info, SET_ALLOW);
|
||||||
ret = 1;
|
ret = 1;
|
||||||
} else if (response.decision == ALLOW_TEMP) {
|
} else if (response.decision == ALLOW_TEMP) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"Permission granted temporarily to %s based on zenty response.\n",
|
"[ICFS] Permission granted temporarily to %s based on zenty "
|
||||||
|
"response.\n",
|
||||||
proc_info.name);
|
proc_info.name);
|
||||||
set_temp_access(real_path, proc_info, SET_ALLOW);
|
set_temp_access(real_path, proc_info, SET_ALLOW);
|
||||||
ret = 1;
|
ret = 1;
|
||||||
} else if (response.decision == DENY_TEMP) {
|
} else if (response.decision == DENY_TEMP) {
|
||||||
fprintf(stderr,
|
fprintf(
|
||||||
"Permission denied temporarily to %s based on zenty response.\n",
|
stderr,
|
||||||
proc_info.name);
|
"[ICFS] Permission denied temporarily to %s based on zenty response.\n",
|
||||||
|
proc_info.name);
|
||||||
set_temp_access(real_path, proc_info, SET_DENY);
|
set_temp_access(real_path, proc_info, SET_DENY);
|
||||||
ret = 0;
|
ret = 0;
|
||||||
} else if (response.decision == DENY) {
|
} else if (response.decision == DENY) {
|
||||||
fprintf(stderr,
|
fprintf(
|
||||||
"Permission denied permanently to %s based on zenty response.\n",
|
stderr,
|
||||||
proc_info.name);
|
"[ICFS] Permission denied permanently to %s based on zenty response.\n",
|
||||||
|
proc_info.name);
|
||||||
set_perm_access(real_path, proc_info, SET_DENY);
|
set_perm_access(real_path, proc_info, SET_DENY);
|
||||||
ret = 0;
|
ret = 0;
|
||||||
}
|
}
|
||||||
|
6
test/stress.bash
Executable file
6
test/stress.bash
Executable file
@ -0,0 +1,6 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
count=$1
|
||||||
|
for i in $(seq $count); do
|
||||||
|
$2 ./protected/haystack/
|
||||||
|
done
|
@ -10,7 +10,7 @@ chmod 777 ./protected/perm777 ./protected/perm000
|
|||||||
echo "Free code, free world." >./protected/motto
|
echo "Free code, free world." >./protected/motto
|
||||||
|
|
||||||
mkdir protected/haystack
|
mkdir protected/haystack
|
||||||
for i in {1..10}; do
|
for i in {1..100}; do
|
||||||
touch "./protected/haystack/hay$i"
|
touch "./protected/haystack/hay$i"
|
||||||
done
|
done
|
||||||
touch ./protected/haystack/needle
|
touch ./protected/haystack/needle
|
||||||
@ -22,7 +22,7 @@ make -C ./opener || (
|
|||||||
echo "Could not make the opener program."
|
echo "Could not make the opener program."
|
||||||
exit 1
|
exit 1
|
||||||
)
|
)
|
||||||
for i in {1..10}; do
|
for i in {1..12}; do
|
||||||
cp ./opener/opener "./openers/opener$i"
|
cp ./opener/opener "./openers/opener$i"
|
||||||
ln --symbolic "$(realpath "./openers/opener$i")" "./openers/symlinked_opener$i"
|
ln --symbolic "$(realpath "./openers/opener$i")" "./openers/symlinked_opener$i"
|
||||||
done
|
done
|
||||||
@ -43,6 +43,12 @@ if [[ $1 == "--setuid" ]]; then
|
|||||||
echo "Valgrind will not be used due to setuid compatibility issues."
|
echo "Valgrind will not be used due to setuid compatibility issues."
|
||||||
../build/icfs -o default_permissions ./protected ./.pt.db &
|
../build/icfs -o default_permissions ./protected ./.pt.db &
|
||||||
sleep 1
|
sleep 1
|
||||||
|
elif [[ $1 == "--performance" ]]; then
|
||||||
|
echo "Database protection will not be tested due to the lack of setuid capabilites."
|
||||||
|
echo "To test it, run this script with '--setuid'."
|
||||||
|
echo "valgrind won't be used to make performance measurements more accurate."
|
||||||
|
../build/icfs -o default_permissions ./protected ./.pt.db &
|
||||||
|
sleep 5
|
||||||
else
|
else
|
||||||
echo "Database protection will not be tested due to the lack of setuid capabilites."
|
echo "Database protection will not be tested due to the lack of setuid capabilites."
|
||||||
echo "To test it, run this script with '--setuid'."
|
echo "To test it, run this script with '--setuid'."
|
||||||
@ -205,9 +211,36 @@ else
|
|||||||
echo "[ICFS-TEST]: permanent permissions database access was not tested due to the lack of seuid bit setting capabilites. To test this, run the script with '--setuid' flag"
|
echo "[ICFS-TEST]: permanent permissions database access was not tested due to the lack of seuid bit setting capabilites. To test this, run the script with '--setuid' flag"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
RUNS_NUM=500
|
||||||
|
|
||||||
|
if [[ $1 == '--performance' ]]; then
|
||||||
|
|
||||||
|
#warmup
|
||||||
|
icfs_dialogue --set-fake-response yes
|
||||||
|
parallel -j8 ::: "./stress.bash $RUNS_NUM openers/opener10"
|
||||||
|
|
||||||
|
icfs_dialogue --set-fake-response yes
|
||||||
|
echo "[ICFS-TEST]: temp permissions"
|
||||||
|
time parallel -j8 ::: "./stress.bash $RUNS_NUM openers/opener7"
|
||||||
|
|
||||||
|
icfs_dialogue --set-fake-response yes_perm
|
||||||
|
echo "[ICFS-TEST]: perm permissions"
|
||||||
|
time parallel -j8 ::: "./stress.bash $RUNS_NUM openers/opener8"
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
# unmount
|
# unmount
|
||||||
|
|
||||||
sleep 0.5
|
sleep 0.5
|
||||||
#lsof +f -- $(realpath ./protected)
|
#lsof +f -- $(realpath ./protected)
|
||||||
umount "$(realpath ./protected)"
|
umount "$(realpath ./protected)"
|
||||||
sleep 2
|
sleep 3
|
||||||
|
|
||||||
|
if [[ $1 == '--performance' ]]; then
|
||||||
|
|
||||||
|
#warmup
|
||||||
|
parallel -j8 ::: "./stress.bash $RUNS_NUM openers/opener9"
|
||||||
|
|
||||||
|
echo "[ICFS-TEST]: bare filesystem"
|
||||||
|
time parallel -j8 ::: "./stress.bash $RUNS_NUM openers/opener9"
|
||||||
|
fi
|
||||||
|
Loading…
x
Reference in New Issue
Block a user