2 Commits

18 changed files with 1028 additions and 4482 deletions

View File

@@ -21,14 +21,14 @@ endif
# set up cflags and libs # set up cflags and libs
CFLAGS := -D_FILE_OFFSET_BITS=64 CFLAGS := -D_FILE_OFFSET_BITS=64 -g
LDFLAGS := LDFLAGS :=
CFLAGS += $(shell pkg-config --cflags $(PACKAGE_NAMES)) CFLAGS += $(shell pkg-config --cflags $(PACKAGE_NAMES))
LDFLAGS += $(shell pkg-config --libs $(PACKAGE_NAMES)) LDFLAGS += $(shell pkg-config --libs $(PACKAGE_NAMES))
ifeq ($(DEBUG),1) ifeq ($(DEBUG),1)
CFLAGS += -O0 -pedantic -g -Wall -Wextra -Wcast-align \ CFLAGS += -O0 -pedantic -Wall -Wextra -Wcast-align \
-Wcast-qual -Wdisabled-optimization -Wformat=2 \ -Wcast-qual -Wdisabled-optimization -Wformat=2 \
-Winit-self -Wlogical-op -Wmissing-declarations \ -Winit-self -Wlogical-op -Wmissing-declarations \
-Wmissing-include-dirs -Wredundant-decls -Wshadow \ -Wmissing-include-dirs -Wredundant-decls -Wshadow \
@@ -71,7 +71,7 @@ $(BUILD_DIR)/main.o: $(SOURCES_DIR)/main.c
$(BUILD_DIR)/fuse_operations.o: $(SOURCES_DIR)/fuse_operations.c $(SOURCES_DIR)/fuse_operations.h $(BUILD_DIR)/fuse_operations.o: $(SOURCES_DIR)/fuse_operations.c $(SOURCES_DIR)/fuse_operations.h
$(CC) $(CFLAGS) -c $< $(LDFLAGS) -o $@ $(CC) $(CFLAGS) -c $< $(LDFLAGS) -o $@
$(BUILD_DIR)/sourcefs.o: $(SOURCES_DIR)/sourcefs.c $(SOURCES_DIR)/sourcefs.h $(SOURCES_DIR)/real_filename.h $(BUILD_DIR)/sourcefs.o: $(SOURCES_DIR)/sourcefs.c $(SOURCES_DIR)/sourcefs.h
$(CC) $(CFLAGS) -c $< $(LDFLAGS) -o $@ $(CC) $(CFLAGS) -c $< $(LDFLAGS) -o $@
$(BUILD_DIR)/ui-socket.o: $(SOURCES_DIR)/ui-socket.c $(SOURCES_DIR)/ui-socket.h $(BUILD_DIR)/ui-socket.o: $(SOURCES_DIR)/ui-socket.c $(SOURCES_DIR)/ui-socket.h

View File

@@ -1,6 +0,0 @@
#ifndef ACCESS_T_H
#define ACCESS_T_H
typedef enum { DENY, ALLOW, ALLOW_TEMP, NDEF } access_t;
#endif // !ACCESS_T_H

4783
src/cc.h

File diff suppressed because it is too large Load Diff

View File

@@ -11,8 +11,6 @@
See the file LICENSE. See the file LICENSE.
*/ */
#include "real_filename.h"
#include <assert.h>
#include <stddef.h> #include <stddef.h>
#define FUSE_USE_VERSION 31 #define FUSE_USE_VERSION 31
@@ -42,7 +40,7 @@
#include "sourcefs.h" #include "sourcefs.h"
#include "ui-socket.h" #include "ui-socket.h"
char *get_process_name_by_pid(const int pid) { const char *get_process_name_by_pid(const int pid) {
char path[1024]; char path[1024];
sprintf(path, "/proc/%d/exe", pid); sprintf(path, "/proc/%d/exe", pid);
@@ -96,6 +94,9 @@ char *get_process_name_by_pid(const int pid) {
*/ */
} }
// TODO: move this somewhere else
const char *real_filename(const char *filename) { return filename; }
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;
@@ -119,7 +120,6 @@ static void *xmp_init(struct fuse_conn_info *conn, struct fuse_config *cfg) {
cfg->attr_timeout = 0; cfg->attr_timeout = 0;
cfg->negative_timeout = 0; cfg->negative_timeout = 0;
fprintf(stderr, "%d\n", getpid()); fprintf(stderr, "%d\n", getpid());
assert(get_mountpoint() != NULL);
return NULL; return NULL;
} }
@@ -157,7 +157,7 @@ static int xmp_access(const char *path, int mask) {
// fprintf(stderr, "%s, %d\n", path, ask_access(path, pi)); // fprintf(stderr, "%s, %d\n", path, ask_access(path, pi));
if (!interactive_access(path, proc_info, 0)) { if (!interactive_access(real_filename(path), proc_info, 0)) {
free((void *)proc_info.name); free((void *)proc_info.name);
return -EACCES; return -EACCES;
} }
@@ -323,7 +323,7 @@ static int xmp_unlink(const char *path) {
// 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, 0)) { if (!interactive_access(real_filename(path), pi, 0)) {
free(pi.name); free(pi.name);
return -EACCES; return -EACCES;
} }
@@ -371,14 +371,15 @@ static int xmp_rename(const char *from, const char *to, unsigned int flags) {
// fprintf(stderr, "%s, %d\n", path, ask_access(path, pi)); // fprintf(stderr, "%s, %d\n", path, ask_access(path, pi));
if (!interactive_access(from, pi, 0)) { if (!interactive_access(real_filename(from), pi, 0)) {
free(pi.name); free(pi.name);
return -EACCES; return -EACCES;
} }
// the "to" file may exist and the process needs to get persmission to modify // the "to" file may exist and the process needs to get persmission to modify
// it // it
if (source_access(to, F_OK) == 0 && !interactive_access(to, pi, 0)) { if (source_access(to, F_OK) == 0 &&
!interactive_access(real_filename(to), pi, 0)) {
free(pi.name); free(pi.name);
return -EACCES; return -EACCES;
} }
@@ -401,7 +402,7 @@ static int xmp_link(const char *from, const char *to) {
pi.name = get_process_name_by_pid(pi.PID); pi.name = get_process_name_by_pid(pi.PID);
// fprintf(stderr, "%s, %d\n", path, ask_access(path, pi)); // fprintf(stderr, "%s, %d\n", path, ask_access(path, pi));
if (!interactive_access(from, pi, 0)) { if (!interactive_access(real_filename(from), pi, 0)) {
free(pi.name); free(pi.name);
return -EACCES; return -EACCES;
} }
@@ -426,7 +427,7 @@ static int xmp_chmod(const char *path, mode_t mode, struct fuse_file_info *fi) {
pi.name = get_process_name_by_pid(pi.PID); pi.name = get_process_name_by_pid(pi.PID);
// 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, 0)) { if (!interactive_access(real_filename(path), pi, 0)) {
free(pi.name); free(pi.name);
return -EACCES; return -EACCES;
} }
@@ -457,7 +458,7 @@ static int xmp_chown(const char *path, uid_t uid, gid_t gid,
pi.name = get_process_name_by_pid(pi.PID); pi.name = get_process_name_by_pid(pi.PID);
// 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, 0)) { if (!interactive_access(real_filename(path), pi, 0)) {
free(pi.name); free(pi.name);
return -EACCES; return -EACCES;
} }
@@ -517,7 +518,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(real_filename(path), pi, GRANT_PERM)) {
free(pi.name); free(pi.name);
return -EACCES; return -EACCES;
} }
@@ -541,7 +542,7 @@ static int xmp_open(const char *path, struct fuse_file_info *fi) {
pi.name = get_process_name_by_pid(pi.PID); pi.name = get_process_name_by_pid(pi.PID);
// 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, 0)) { if (!interactive_access(real_filename(path), pi, 0)) {
free(pi.name); free(pi.name);
return -EACCES; return -EACCES;
} }

View File

@@ -1,69 +0,0 @@
SHELL=/bin/bash
# configurable options
SOURCES_DIR := .
TESTS_DIR := .
BUILD_DIR := .
CC := gcc
CXX := g++
# dependencies
PACKAGE_NAMES := gtk4 libadwaita-1
ifeq ($(TEST), 1)
# PACKAGE_NAMES += check # TODO: use check?
endif
# set up cflags and libs
CFLAGS := -D_FILE_OFFSET_BITS=64
LDFLAGS :=
CFLAGS += $(shell pkg-config --cflags $(PACKAGE_NAMES))
LDFLAGS += $(shell pkg-config --libs $(PACKAGE_NAMES))
ifeq ($(DEBUG),1)
CFLAGS += -O0 -pedantic -g -Wall -Wextra -Wcast-align \
-Wcast-qual -Wdisabled-optimization -Wformat=2 \
-Winit-self -Wlogical-op -Wmissing-declarations \
-Wmissing-include-dirs -Wredundant-decls -Wshadow \
-Wsign-conversion -Wstrict-overflow=5 \
-Wswitch-default -Wundef -Wno-unused
LDFLAGS +=
else
CFLAGS += -O3
LDFLAGS +=
endif
# set up targets
TARGETS := $(BUILD_DIR)/zenity
ifeq ($(TEST), 1)
TARGETS += zenity_test
endif
# build!
default: $(TARGETS)
.PHONY: clean zenity_test
zenity_test: $(BUILD_DIR)/zenity
./zenity 666 cat /home/fedir Downloads
$(BUILD_DIR)/zenity: $(BUILD_DIR)/zenity.o
$(CC) $(CFLAGS) $^ $(LDFLAGS) -o $(BUILD_DIR)/zenity
$(BUILD_DIR)/zenity.o: $(SOURCES_DIR)/zenity-clone.c
$(CC) $(CFLAGS) -c $< $(LDFLAGS) -o $(BUILD_DIR)/zenity.o
clean:
rm $(BUILD_DIR)/*.o $(BUILD_DIR)/zenity

View File

@@ -1,153 +0,0 @@
#include "gio/gio.h"
#include "glib-object.h"
#include "glib.h"
#include <adwaita.h>
#include <gtk/gtk.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#define YES 0
#define NO 1
#define PERM 2
int exit_code = 0;
gboolean is_permanent = false;
GtkEntryBuffer *entry_buffer = NULL;
GtkWidget *checkbox = NULL;
static void negative_response(GtkWindow *window) {
fprintf(stdout, "%s", gtk_entry_buffer_get_text(entry_buffer));
exit_code = (gtk_check_button_get_active(GTK_CHECK_BUTTON(checkbox)))
? YES | PERM
: YES;
gtk_window_close(window);
}
static void positive_response(GtkWindow *window) {
fprintf(stdout, "%s", gtk_entry_buffer_get_text(entry_buffer));
exit_code = (gtk_check_button_get_active(GTK_CHECK_BUTTON(checkbox)))
? NO | PERM
: NO;
gtk_window_close(window);
}
static void on_check_button_toggled(GtkToggleButton *button,
gpointer user_data) {
gboolean active = gtk_toggle_button_get_active(button);
}
static void on_activate(GtkApplication *app, gpointer user_data) {
// Create the main window
AdwWindow *window = ADW_WINDOW(adw_window_new());
gtk_window_set_application(GTK_WINDOW(window), app);
gtk_window_set_title(GTK_WINDOW(window), "icfs");
// gtk_window_set_default_size(GTK_WINDOW(window), 300, 150);
AdwStatusPage *content = ADW_STATUS_PAGE(adw_status_page_new());
adw_status_page_set_title(content, "Allow access?");
char *description = NULL;
asprintf(
&description,
"Allow process <tt>%s</tt> with PID <tt>%s</tt> to access <tt>%s</tt>",
g_object_get_data(G_OBJECT(app), "accessing_name"),
g_object_get_data(G_OBJECT(app), "accessing_pid"),
g_object_get_data(G_OBJECT(app), "access_dir"));
adw_status_page_set_description(content, description);
free(description);
entry_buffer = gtk_entry_buffer_new(
g_object_get_data(G_OBJECT(app), "access_dir"),
strlen(g_object_get_data(G_OBJECT(app), "access_dir")));
GtkWidget *entry = gtk_entry_new();
gtk_entry_set_buffer(GTK_ENTRY(entry), entry_buffer);
gtk_entry_set_placeholder_text(GTK_ENTRY(entry), "Enter filename");
gtk_widget_set_hexpand(entry, TRUE);
// Create a prefix label and box
GtkWidget *entry_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
GtkWidget *prefix_label =
gtk_label_new(g_object_get_data(G_OBJECT(app), "root_folder"));
gtk_box_append(GTK_BOX(entry_box), prefix_label);
gtk_box_append(GTK_BOX(entry_box), entry);
checkbox = gtk_check_button_new_with_label("Permanent");
gtk_check_button_set_active(GTK_CHECK_BUTTON(checkbox), false);
// gtk_widget_set_halign(checkbox, GTK_ALIGN_CENTER);
GtkWidget *yes_button = gtk_button_new_with_label("Yes");
gtk_widget_set_hexpand(yes_button, TRUE);
g_signal_connect_swapped(yes_button, "clicked", G_CALLBACK(positive_response),
window);
GtkWidget *no_button = gtk_button_new_with_label("No");
gtk_widget_set_hexpand(no_button, TRUE);
g_signal_connect_swapped(no_button, "clicked", G_CALLBACK(negative_response),
window);
GtkWidget *button_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6);
gtk_box_append(GTK_BOX(button_box), yes_button);
gtk_box_append(GTK_BOX(button_box), no_button);
gtk_widget_set_halign(button_box, GTK_ALIGN_FILL);
// Combine everything in a box
GtkWidget *box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 12);
gtk_box_append(GTK_BOX(box), GTK_WIDGET(content));
gtk_box_append(GTK_BOX(box), entry_box);
gtk_box_append(GTK_BOX(box), checkbox);
gtk_box_append(GTK_BOX(box), button_box);
gtk_widget_set_margin_top(GTK_WIDGET(box), 12);
gtk_widget_set_margin_bottom(GTK_WIDGET(box), 12);
gtk_widget_set_margin_start(GTK_WIDGET(box), 12);
gtk_widget_set_margin_end(GTK_WIDGET(box), 12);
// g_signal_connect(window, "response", G_CALLBACK(gtk_window_close), window);
// Show the dialog
adw_window_set_content(window, box);
gtk_window_present(GTK_WINDOW(window));
}
static int on_command_line(GApplication *app, GApplicationCommandLine *cmdline,
gpointer user_data) {
gchar **argv;
gint argc;
argv = g_application_command_line_get_arguments(cmdline, &argc);
// Handle your arguments here
if (argc >= 4) {
fprintf(stderr, "%s\n", argv[1]);
g_object_set_data_full(G_OBJECT(app), "accessing_pid", g_strdup(argv[1]),
g_free);
g_object_set_data_full(G_OBJECT(app), "accessing_name", g_strdup(argv[2]),
g_free);
g_object_set_data_full(G_OBJECT(app), "root_folder", g_strdup(argv[3]),
g_free);
g_object_set_data_full(G_OBJECT(app), "access_dir", g_strdup(argv[4]),
g_free);
}
g_strfreev(argv);
// Activate the application
g_application_activate(app);
return 0;
}
int main(int argc, char **argv) {
// Create a new application
AdwApplication *app = adw_application_new("com.example.zenityclone",
G_APPLICATION_HANDLES_COMMAND_LINE);
g_signal_connect(app, "command-line", G_CALLBACK(on_command_line), NULL);
g_signal_connect(app, "activate", G_CALLBACK(on_activate), NULL);
// Run the application
int status = g_application_run(G_APPLICATION(app), argc, argv);
g_object_unref(app);
return (status == 0) ? exit_code : status;
}

View File

@@ -56,7 +56,6 @@ int main(int argc, char *argv[]) {
ret = fuse_main(argc - 1, argv, get_fuse_operations(), NULL); ret = fuse_main(argc - 1, argv, get_fuse_operations(), NULL);
free((void *)mountpoint); free((void *)mountpoint);
source_destroy();
destroy_ui_socket(); destroy_ui_socket();
return ret; return ret;
} }

View File

@@ -7,7 +7,6 @@
*/ */
#include "perm_permissions_table.h" #include "perm_permissions_table.h"
#include "access_t.h"
#include "process_info.h" #include "process_info.h"
#include <fcntl.h> #include <fcntl.h>
#include <pthread.h> #include <pthread.h>
@@ -24,10 +23,11 @@
sqlite3 *perm_database = NULL; sqlite3 *perm_database = NULL;
const char *const table_name = "permissions"; const char *const table_name = "permissions";
// one row corresponds to a permission to access one file for one executable // one row corresponds to a permission to access one file for one executable
const int column_count = 3; const int column_count = 2;
const char *const schema[] = {"executable", "filename", "mode"}; const char *const schema[] = {"executable", "filename"};
const char *const types[] = {"TEXT", "TEXT", "INTEGER"}; const char *const types[] = {"TEXT", "TEXT"};
uid_t ruid, euid, current_pid; uid_t ruid, euid, current_pid;
sqlite3_stmt *perm_check_statement = NULL;
pthread_mutex_t uid_switch = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t uid_switch = PTHREAD_MUTEX_INITIALIZER;
void set_db_fsuid() { void set_db_fsuid() {
@@ -70,10 +70,9 @@ static int check_table_col_schema(void *notused, int argc, char **argv,
} }
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, "Table contains more columns than expected.\n");
return 1; return 1;
} }
if (strcmp(schema[column_num], argv[1]) == 0 && if (strcmp(schema[column_num], argv[1]) == 0 &&
strcmp(types[column_num], argv[2]) == 0) { strcmp(types[column_num], argv[2]) == 0) {
return 0; return 0;
@@ -92,9 +91,8 @@ 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, "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);";
"NULL, filename TEXT NOT NULL, mode INTEGER NOT NULL);";
char *err = NULL; char *err = NULL;
int ret = sqlite3_exec(perm_database, create_query, NULL, NULL, &err); int ret = sqlite3_exec(perm_database, create_query, NULL, NULL, &err);
@@ -144,6 +142,45 @@ int ensure_database_schema() {
return 0; return 0;
} }
int prepare_sql_queries() {
const char *query_template =
"SELECT * FROM %s WHERE executable = ? AND filename = ?;";
char *query_string = NULL;
int query_len = snprintf(NULL, 0, query_template, table_name) + 1;
if (query_len < 0) {
fprintf(stderr, "Failed to prepare statement");
perror("");
return 1;
}
query_string = malloc(query_len);
if (query_string == NULL) {
fprintf(stderr, "Failed to allocate memory for the query");
perror("");
return 1;
}
int ret = snprintf(query_string, query_len, query_template, table_name);
if (ret < 0) {
fprintf(stderr, "Failed to prepare statement");
perror("");
free(query_string);
return 1;
}
if (sqlite3_prepare_v2(perm_database, query_string, -1, &perm_check_statement,
NULL) != SQLITE_OK) {
fprintf(stderr, "Failed to prepare statement: %s\n",
sqlite3_errmsg(perm_database));
free(query_string);
return 1;
}
free(query_string);
return 0;
}
void free_sql_queries(void) { sqlite3_finalize(perm_check_statement); }
/** /**
* Initializes the permanent permissions table. * Initializes the permanent permissions table.
* *
@@ -172,58 +209,61 @@ int init_perm_permissions_table(const char *db_filename) {
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, "Couldn't set euid to ruid.\n");
exit(status); exit(status);
} }
if (prepare_sql_queries()) {
fprintf(stderr, "Couldn't prepare sql queries.\n");
exit(status);
}
return 0; return 0;
} }
/** /**
* Destroys the permanent permissions table. * Destroys the permanent permissions table.
*/ */
void destroy_perm_permissions_table() { sqlite3_close(perm_database); } void destroy_perm_permissions_table(void) {
free_sql_queries();
sqlite3_close(perm_database);
}
/** /**
* Checks if the process has a permanent access to the file. * Checks if the process has a permanent access to the file.
* *
* @param filename: The file that the process is trying to access * @param filename: The file that the process is trying to access
* @pram pi: The process information * @pram pi: The process information
* @return: access status - ALLOW, DENY or NDEF in case if no information was * @return: 0 if access is denied, 1 if access is allowed
* found
*/ */
access_t check_perm_access(const char *filename, struct process_info pi) { int check_perm_access(const char *filename, struct process_info pi) {
size_t query_len =
char *query = NULL; 56 + strlen(table_name) + strlen(filename) + strlen(pi.name);
int ret = asprintf(&query, const char *query = malloc(query_len);
"SELECT * FROM %s WHERE executable = \'%s\' " size_t should_be_written = snprintf(
"AND filename = \'%s\' AND mode = TRUE;", query, query_len,
table_name, pi.name, filename); "SELECT * FROM %s WHERE executable = \'%s\' AND filename = \'%s\';",
table_name, pi.name, filename);
if (ret < 0) { // -1 for the \0
// If asprintf fails, the contents of query are undefined (see man if (should_be_written != query_len - 1) {
// asprintf). That does not explicitly rule out that query will be a valid fprintf(stderr,
// pointer. But the risk of freeing a non-allocated pointer is too much to "Unexpected query size while permanent access rule check: "
// justify preparing for this. "Expected %lu, but snprintf returned %lu. The query: %s\n",
fprintf(stderr, "Could not create query on access check"); query_len, should_be_written, query);
perror(""); return 0;
return NDEF;
} }
char *sqlite_error = NULL; char *sqlite_error = NULL;
int flag = 0; int flag = 0;
ret = sqlite3_exec(perm_database, query, set_flag, &flag, &sqlite_error); int ret = sqlite3_exec(perm_database, query, set_flag, &flag, &sqlite_error);
free((void *)query);
if (ret != SQLITE_OK) { if (ret != SQLITE_OK) {
fprintf(stderr, "SQLite returned an error: %s\n", sqlite_error); fprintf(stderr, "SQLite returned an error: %s\n", sqlite_error);
sqlite3_free(sqlite_error); sqlite3_free(sqlite_error);
return NDEF; free(query);
return 0;
} }
if (flag) { free(query);
return ALLOW; return flag;
}
return NDEF;
} }
/** /**
@@ -234,23 +274,23 @@ access_t check_perm_access(const char *filename, struct process_info pi) {
* @return: 0 on success, 1 on failure * @return: 0 on success, 1 on failure
*/ */
int give_perm_access(const char *filename, struct process_info pi) { int give_perm_access(const char *filename, struct process_info pi) {
char *query = NULL; size_t query_len =
int ret = asprintf(&query, "INSERT INTO %s VALUES (\'%s\', \'%s\', TRUE);", 30 + strlen(table_name) + strlen(filename) + strlen(pi.name);
table_name, pi.name, filename); const char *query = malloc(query_len);
size_t should_be_written =
if (ret < 0) { snprintf(query, query_len, "INSERT INTO %s VALUES (\'%s\', \'%s\');",
// If asprintf fails, the contents of query are undefined (see man table_name, pi.name, filename);
// asprintf). That does not explicitly rule out that query will be a valid // -1 for the \0
// pointer. But the risk of freeing a non-allocated pointer is too much to if (should_be_written != query_len - 1) {
// justify preparing for this. fprintf(stderr,
fprintf(stderr, "Could not create query on rule insertion"); "Unexpected query size while permanent access rule insertion: "
perror(""); "Expected %lu, but snprintf returned %lu\n",
query_len, should_be_written);
return 1; return 1;
} }
char *sqlite_error = NULL; char *sqlite_error = NULL;
ret = sqlite3_exec(perm_database, query, NULL, NULL, &sqlite_error); int ret = sqlite3_exec(perm_database, query, NULL, NULL, &sqlite_error);
free(query);
if (ret != SQLITE_OK) { if (ret != SQLITE_OK) {
fprintf(stderr, "SQLite returned an error: %s\n", sqlite_error); fprintf(stderr, "SQLite returned an error: %s\n", sqlite_error);
sqlite3_free(sqlite_error); sqlite3_free(sqlite_error);
@@ -258,5 +298,6 @@ int give_perm_access(const char *filename, struct process_info pi) {
return 1; return 1;
} }
free(query);
return 0; return 0;
} }

View File

@@ -9,7 +9,6 @@
#ifndef PERM_PERMISSION_TABLE_H #ifndef PERM_PERMISSION_TABLE_H
#define PERM_PERMISSION_TABLE_H #define PERM_PERMISSION_TABLE_H
#include "access_t.h"
#include "process_info.h" #include "process_info.h"
/** /**
@@ -30,10 +29,9 @@ void destroy_perm_permissions_table();
* *
* @param filename: The file that the process is trying to access * @param filename: The file that the process is trying to access
* @pram pi: The process information * @pram pi: The process information
* @return: access status - ALLOW, DENY or NDEF in case if no information was * @return: 0 if access is denied, 1 if access is allowed
* found
*/ */
access_t check_perm_access(const char *filename, struct process_info pi); int check_perm_access(const char *filename, struct process_info pi);
/** /**
* Gives permanent access to the process to the file. * Gives permanent access to the process to the file.

View File

@@ -12,7 +12,7 @@
#include <sys/types.h> #include <sys/types.h>
struct process_info { struct process_info {
pid_t PID; pid_t PID;
char *name; const char *name;
}; };
#endif // PROCESS_INFO_H #endif // PROCESS_INFO_H

View File

@@ -1,7 +0,0 @@
#ifndef REAL_FILENAME_H
#define REAL_FILENAME_H
const char *real_filename(const char *filename);
const char *get_mountpoint(void);
#endif // !REAL_FILENAME_H

View File

@@ -10,14 +10,14 @@
#include "sourcefs.h" #include "sourcefs.h"
#include <dirent.h> #include <dirent.h>
#include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/stat.h>
#include <unistd.h> #include <unistd.h>
static struct source_files_handle { static struct source_files_handle {
const char *mountpoint;
int root_fd; int root_fd;
} handle; } handle;
@@ -30,14 +30,6 @@ 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);
if (handle.mountpoint == NULL) {
perror("Malloc failed");
return -1;
}
strcpy(handle.mountpoint, 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) {
@@ -51,32 +43,6 @@ int source_init(const char *root_path) {
return 0; return 0;
} }
void source_destroy(void) { free(handle.mountpoint); }
const char *get_mountpoint(void) { return handle.mountpoint; }
const char *real_filename(const char *filename) {
const char *mountpoint = get_mountpoint();
// Calculate required length
size_t len1 = strlen(mountpoint);
size_t len2 = strlen(filename);
size_t total_len = len1 + len2;
// Allocate memory (+1 for null terminator)
char *result = malloc(total_len + 1);
if (result == NULL) {
fprintf(stderr, "Memory allocation failed");
perror("");
return NULL;
}
// Copy strings
strcpy(result, mountpoint);
strcat(result, filename);
return result;
}
int source_mkdir(const char *filename, mode_t mode) { int source_mkdir(const char *filename, mode_t mode) {
const char *relative_filename = source_filename_translate(filename); const char *relative_filename = source_filename_translate(filename);
return mkdirat(handle.root_fd, relative_filename, mode); return mkdirat(handle.root_fd, relative_filename, mode);

View File

@@ -19,7 +19,6 @@
* @return 0 on success, -1 on failure. * @return 0 on success, -1 on failure.
*/ */
int source_init(const char *root_path); int source_init(const char *root_path);
void source_destroy(void);
/* All of the functions below are designed to behave exactly as their non-source /* All of the functions below are designed to behave exactly as their non-source
* counterparts. */ * counterparts. */

View File

@@ -7,7 +7,6 @@
*/ */
#include "temp_permissions_table.h" #include "temp_permissions_table.h"
#include "access_t.h"
#include "cc.h" #include "cc.h"
#include "process_info.h" #include "process_info.h"
#include <pthread.h> #include <pthread.h>
@@ -19,7 +18,6 @@ struct temp_process_permissions {
// proc_pid_stat(5)) // proc_pid_stat(5))
unsigned long long creation_time; unsigned long long creation_time;
vec(char *) allowed_files; vec(char *) allowed_files;
vec(char *) denied_files;
}; };
map(pid_t, struct temp_process_permissions) temp_permissions_table; map(pid_t, struct temp_process_permissions) temp_permissions_table;
@@ -35,8 +33,8 @@ pthread_mutex_t temp_permissions_table_lock;
* never really equal to 0, it exceptionally unlikely. * never really equal to 0, it exceptionally unlikely.
*/ */
unsigned long long get_process_creation_time(pid_t pid) { unsigned long long get_process_creation_time(pid_t pid) {
char path[256]; char path[32];
FILE *fp = NULL; FILE *fp;
unsigned long long creation_time = 0; unsigned long long creation_time = 0;
// Construct the path to the process's status file // Construct the path to the process's status file
@@ -74,7 +72,7 @@ unsigned long long get_process_creation_time(pid_t pid) {
* *
* @return: 0 on success, -1 on failure (e.g. ENOMEM) * @return: 0 on success, -1 on failure (e.g. ENOMEM)
*/ */
int init_temp_permissions_table(void) { int init_temp_permissions_table() {
pthread_mutex_init(&temp_permissions_table_lock, PTHREAD_MUTEX_DEFAULT); pthread_mutex_init(&temp_permissions_table_lock, PTHREAD_MUTEX_DEFAULT);
init(&temp_permissions_table); init(&temp_permissions_table);
return 0; return 0;
@@ -83,21 +81,14 @@ int init_temp_permissions_table(void) {
/** /**
* Destroys the temporary permissions table. * Destroys the temporary permissions table.
* *
* @note: the table is guranteed to be destroyed if it is already initialized. * @note: the table is guranteed to be destroyed if it is already initialized
* It does not indicate any errors whatsoever. If something goes wrong - you are
* screwed.
*/ */
void destroy_temp_permissions_table(void) { void destroy_temp_permissions_table() {
// free the memory allocated for the table // free the memory allocated for the table
for_each(&temp_permissions_table, entry) { for_each(&temp_permissions_table, entry) {
for_each(&entry->allowed_files, allowed_file) { free(*allowed_file); } for_each(&entry->allowed_files, allowed_file) { free(*allowed_file); }
cleanup(&entry->allowed_files); cleanup(&entry->allowed_files);
} }
for_each(&temp_permissions_table, entry) {
for_each(&entry->denied_files, denied_file) { free(*denied_file); }
cleanup(&entry->denied_files);
}
cleanup(&temp_permissions_table); cleanup(&temp_permissions_table);
pthread_mutex_destroy(&temp_permissions_table_lock); pthread_mutex_destroy(&temp_permissions_table_lock);
} }
@@ -107,10 +98,10 @@ void destroy_temp_permissions_table(void) {
* *
* @param filename: The file that the process is trying to access * @param filename: The file that the process is trying to access
* @pram pid: PID of the process * @pram pid: PID of the process
* @return: access status - ALLOW, DENY or NDEF in case if no information was * @return: 0 if access is denied, 1 if access is allowed
* found is avaliable
*/ */
access_t check_temp_access_noparent(const char *filename, pid_t pid) {
int check_temp_access_noparent(const char *filename, pid_t pid) {
// TODO: more efficient locking // TODO: more efficient locking
pthread_mutex_lock(&temp_permissions_table_lock); pthread_mutex_lock(&temp_permissions_table_lock);
struct temp_process_permissions *permission_entry = struct temp_process_permissions *permission_entry =
@@ -120,28 +111,22 @@ access_t check_temp_access_noparent(const char *filename, pid_t pid) {
if (process_creation_time == 0) { if (process_creation_time == 0) {
perror("Could not retrieve process creation time"); perror("Could not retrieve process creation time");
pthread_mutex_unlock(&temp_permissions_table_lock); pthread_mutex_unlock(&temp_permissions_table_lock);
return NDEF; return 0;
} }
if (process_creation_time == permission_entry->creation_time) { if (process_creation_time == permission_entry->creation_time) {
// the process is the same as the one that was granted temporary access // the process is the same as the one that was granted temporary access
// to the file // to the file
for_each(&permission_entry->denied_files, denied_file) {
if (strncmp(*denied_file, filename, strlen(filename)) == 0) {
pthread_mutex_unlock(&temp_permissions_table_lock);
return DENY;
}
}
for_each(&permission_entry->allowed_files, allowed_file) { for_each(&permission_entry->allowed_files, allowed_file) {
if (strncmp(*allowed_file, filename, strlen(filename)) == 0) { if (strncmp(*allowed_file, filename, strlen(filename)) == 0) {
pthread_mutex_unlock(&temp_permissions_table_lock); pthread_mutex_unlock(&temp_permissions_table_lock);
return ALLOW; return 1;
} }
} }
} }
} }
pthread_mutex_unlock(&temp_permissions_table_lock); pthread_mutex_unlock(&temp_permissions_table_lock);
return NDEF; return 0;
} }
/** /**
@@ -180,36 +165,31 @@ pid_t get_parent_pid(pid_t pid) {
* *
* @param filename: The file that the process is trying to access * @param filename: The file that the process is trying to access
* @pram pi: The process information * @pram pi: The process information
* @return: access status - ALLOW, DENY or NDEF in case if no information was * @return: 0 if access is denied, 1 if access is allowed
* found. Does not return ALLOW_TEMP.
* @note: In case one of the parent processes is killed while this function * @note: In case one of the parent processes is killed while this function
* execution the result is not guranteed to be correct. It should only lead to * execution the result is not guranteed to be correct. It should only lead to
* false negatives, though. * false negatives, though.
*/ */
access_t check_temp_access(const char *filename, struct process_info pi) { int check_temp_access(const char *filename, struct process_info pi) {
pid_t current_pid = pi.PID; pid_t current_pid = pi.PID;
while (current_pid != 0) { while (current_pid != 0) {
access_t access = check_temp_access_noparent(filename, current_pid); if (check_temp_access_noparent(filename, current_pid)) {
if (access != NDEF) { return 1;
return access;
} }
current_pid = get_parent_pid(current_pid); current_pid = get_parent_pid(current_pid);
} }
return NDEF; return 0;
} }
/** /**
* Sets temporary access mode of the process to the file. * Gives temporary access to the process to the file.
* *
* @param filename: The file that the process is trying to access * @param filename: The file that the process is trying to access
* @param pi: The process information * @param pi: The process information
* @param mode: Kind of access rule to be set - SET_DENY to deny access, and * @return: 0 on success, -1 on failure (e.g. ENOMEM)
* SET_ALLOW to allow access.
* @return: 0 on success, -1 on failure.
*/ */
int set_temp_access(const char *filename, struct process_info pi, int give_temp_access(const char *filename, struct process_info pi) {
set_mode_t mode) {
pthread_mutex_lock(&temp_permissions_table_lock); pthread_mutex_lock(&temp_permissions_table_lock);
struct temp_process_permissions *permission_entry = struct temp_process_permissions *permission_entry =
get(&temp_permissions_table, pi.PID); get(&temp_permissions_table, pi.PID);
@@ -227,13 +207,7 @@ int set_temp_access(const char *filename, struct process_info pi,
if (process_creation_time == permission_entry->creation_time) { if (process_creation_time == permission_entry->creation_time) {
// the process is the same as the one that was granted temporary access // the process is the same as the one that was granted temporary access
// to the file // to the file
if (mode == SET_ALLOW) { push(&permission_entry->allowed_files, strdup(filename));
push(&permission_entry->allowed_files, strdup(filename));
}
if (mode == SET_DENY) {
push(&permission_entry->denied_files, strdup(filename));
}
pthread_mutex_unlock(&temp_permissions_table_lock); pthread_mutex_unlock(&temp_permissions_table_lock);
return 0; return 0;
} }
@@ -249,13 +223,7 @@ int set_temp_access(const char *filename, struct process_info pi,
new_permission_entry.creation_time = get_process_creation_time(pi.PID); new_permission_entry.creation_time = get_process_creation_time(pi.PID);
init(&new_permission_entry.allowed_files); init(&new_permission_entry.allowed_files);
init(&new_permission_entry.denied_files); push(&new_permission_entry.allowed_files, strdup(filename));
if (mode == SET_ALLOW) {
push(&new_permission_entry.allowed_files, strdup(filename));
}
if (mode == SET_DENY) {
push(&new_permission_entry.denied_files, strdup(filename));
}
insert(&temp_permissions_table, pi.PID, new_permission_entry); insert(&temp_permissions_table, pi.PID, new_permission_entry);

View File

@@ -2,7 +2,6 @@
#ifndef TEMP_PERMISSIONS_TABLE_H #ifndef TEMP_PERMISSIONS_TABLE_H
#define TEMP_PERMISSIONS_TABLE_H #define TEMP_PERMISSIONS_TABLE_H
#include "access_t.h"
#include "process_info.h" #include "process_info.h"
/** /**
@@ -10,43 +9,31 @@
* *
* @return: 0 on success, -1 on failure (e.g. ENOMEM) * @return: 0 on success, -1 on failure (e.g. ENOMEM)
*/ */
int init_temp_permissions_table(void); int init_temp_permissions_table();
/** /**
* Destroys the temporary permissions table. * Destroys the temporary permissions table.
* *
* @note: the table is guranteed to be destroyed if it is already initialized. * @note: the table is guranteed to be destroyed if it is already initialized
* It does not indicate any errors whatsoever. If something goes wrong - you are
* screwed.
*/ */
void destroy_temp_permissions_table(void); void destroy_temp_permissions_table();
/** /**
* Checks if the process or any of it's parents have temporary access to the * Checks if the process has a temporary access to the file.
* file.
*
* @param filename: The file that the process is trying to access
* @pram pi: The process information
* @return: access status - ALLOW, DENY or NDEF in case if no information was
* found. Does not return ALLOW_TEMP.
* @note: In case one of the parent processes is killed while this function
* execution the result is not guranteed to be correct. It should only lead to
* false negatives, though.
*/
access_t check_temp_access(const char *filename, struct process_info pi);
typedef enum { SET_DENY, SET_ALLOW } set_mode_t;
/**
* Sets temporary access mode of the process to the file.
* *
* @param filename: The file that the process is trying to access * @param filename: The file that the process is trying to access
* @param pi: The process information * @param pi: The process information
* @param mode: Kind of access rule to be set - SET_DENY to deny access, and * @return: 0 if access is denied, 1 if access is allowed
* SET_ALLOW to allow access.
* @return: 0 on success, -1 on failure.
*/ */
int set_temp_access(const char *filename, struct process_info pi, int check_temp_access(const char *filename, struct process_info pi);
set_mode_t mode);
/**
* Gives temporary access to the process to the file.
*
* @param filename: The file that the process is trying to access
* @param pi: The process information
* @return: 0 on success, -1 on failure (e.g. ENOMEM)
*/
int give_temp_access(const char *filename, struct process_info pi);
#endif // !TEMP_PERMISSIONS_TABLE_H #endif // !TEMP_PERMISSIONS_TABLE_H

View File

@@ -6,14 +6,11 @@
See the file LICENSE. See the file LICENSE.
*/ */
#include "access_t.h"
#include <stddef.h> #include <stddef.h>
#include <sys/types.h> #include <sys/types.h>
#include <time.h> #include <time.h>
#define _GNU_SOURCE #define _GNU_SOURCE
#include "cc.h"
#include "perm_permissions_table.h" #include "perm_permissions_table.h"
#include "real_filename.h"
#include "temp_permissions_table.h" #include "temp_permissions_table.h"
#include "ui-socket.h" #include "ui-socket.h"
#include <pthread.h> #include <pthread.h>
@@ -24,9 +21,7 @@
#include <sys/un.h> #include <sys/un.h>
#include <unistd.h> #include <unistd.h>
#define ZENITY_YES 0 #define ZENITY_TEMP_ALLOW_MESSAGE "Allow this time\n"
#define ZENITY_NO 1
#define ZENITY_PERM 2
int init_ui_socket(const char *perm_permissions_db_filename) { int init_ui_socket(const char *perm_permissions_db_filename) {
FILE *fp = NULL; FILE *fp = NULL;
@@ -63,24 +58,19 @@ void destroy_ui_socket(void) {
* *
* @param filename: The file that the process is trying to access * @param filename: The file that the process is trying to access
* @param pi: The process information * @param pi: The process information
* @return: access status - ALLOW, DENY or ALLOW_TEMP * @return: 0 if access is denied, 1 if access is allowed, 2 if access is
* allowed for the runtime of the process * allowed for the runtime of the process
*/ */
access_t ask_access(const char *filename, struct process_info proc_info) { int ask_access(const char *filename, struct process_info proc_info) {
FILE *fp = NULL; FILE *fp = NULL;
char *command = NULL; size_t command_len =
int ret = asprintf(&command, "zenity \"%d\" \"%s\" \"%s\" \"%s\"", 139 + sizeof(pid_t) * 8 + strlen(proc_info.name) + strlen(filename);
proc_info.PID, proc_info.name, filename, get_mountpoint()); char *command = (char *)malloc(command_len);
snprintf(command, command_len,
if (ret < 0) { "zenity --question --extra-button \"Allow this time\" --title "
// If asprintf fails, the contents of command are undefined (see man "\"Allow Access?\" --text \"Allow process "
// asprintf). That does not explicitly rule out that command will be a valid "<tt>%s</tt> with PID <tt>%d</tt> to access <tt>%s</tt>\"",
// pointer. But the risk of freeing a non-allocated pointer is too much to proc_info.name, proc_info.PID, filename);
// justify preparing for this.
fprintf(stderr, "Could not create query on rule insertion");
perror("");
return 1;
}
// Zenity Question Message Popup // Zenity Question Message Popup
fp = popen(command, "r"); fp = popen(command, "r");
@@ -88,35 +78,29 @@ access_t ask_access(const char *filename, struct process_info proc_info) {
if (fp == NULL) { if (fp == NULL) {
perror("Pipe returned a error"); perror("Pipe returned a error");
return DENY; return -1;
} }
str(char) zenity_output; // if the user clicks the "Allow this time" button, `zenity` will only
init(&zenity_output); // write it to `stdout`, but the exit code will still be `1`. So, we need
// to manually check the output.
size_t total_read = 0; char buffer[sizeof(ZENITY_TEMP_ALLOW_MESSAGE) + 1];
char line[1024]; // Buffer to read individual lines while (fgets(buffer, sizeof(buffer), fp)) {
printf("%s", buffer);
// Read the command output line by line if (strcmp(buffer, ZENITY_TEMP_ALLOW_MESSAGE) == 0) {
while (fgets(line, sizeof(line), fp)) { pclose(fp);
size_t line_len = strlen(line); return 2;
push_fmt(&zenity_output, line); }
} }
int zenity_exit_code = WEXITSTATUS(pclose(fp)); int zenity_exit_code = WEXITSTATUS(pclose(fp));
fprintf(stderr, "zenity wrote out %s\n", first(&zenity_output));
fprintf(stderr, "zenity returned %d\n", zenity_exit_code); fprintf(stderr, "zenity returned %d\n", zenity_exit_code);
// zenity returns 1 on "No" >:(
cleanup(&zenity_output); if (zenity_exit_code == 0) {
return 1;
if (zenity_exit_code == (ZENITY_YES | ZENITY_PERM)) {
return ALLOW;
}
if (zenity_exit_code == ZENITY_YES) {
return ALLOW_TEMP;
} }
return DENY; return 0;
} }
/** /**
@@ -132,62 +116,38 @@ access_t ask_access(const char *filename, struct process_info proc_info) {
*/ */
int interactive_access(const char *filename, struct process_info proc_info, int interactive_access(const char *filename, struct process_info proc_info,
int opts) { int opts) {
char *real_path = real_filename(filename);
access_t access = check_temp_access(real_path, proc_info); if (check_temp_access(filename, proc_info) ||
if (access == ALLOW) { check_perm_access(filename, proc_info)) {
free(real_path); // access was already granted before
return 1; return 1;
} }
if (access == DENY) {
free(real_path);
return 0;
}
access = check_perm_access(real_path, proc_info);
if (access == ALLOW) {
free(real_path);
return 1;
}
if (access == DENY) {
free(real_path);
return 0;
}
// if noth GRANT_TEMP and GRANT_PERM are selected, then only permanent // if noth GRANT_TEMP and GRANT_PERM are selected, then only permanent
// permissions are granted // permissions are granted
if (opts & GRANT_PERM) { if (opts & GRANT_PERM) {
give_perm_access(real_path, proc_info); give_perm_access(filename, proc_info);
free(real_path);
return 1; return 1;
} }
if (opts & GRANT_TEMP) { if (opts & GRANT_TEMP) {
set_temp_access(real_path, proc_info, SET_ALLOW); give_temp_access(filename, proc_info);
free(real_path);
return 1; return 1;
} }
access_t user_response = ask_access(real_path, proc_info); int user_response = ask_access(filename, proc_info);
if (user_response == ALLOW) { if (user_response == 1) {
give_perm_access(real_path, proc_info); // user said "yes"
free(real_path); give_perm_access(filename, proc_info);
return 1; return 1;
} }
if (user_response == ALLOW_TEMP) { if (user_response == 2) {
set_temp_access(real_path, proc_info, SET_ALLOW); // user said "yes, but only this time"
free(real_path); give_temp_access(filename, proc_info);
return 1; return 1;
} }
if (user_response == DENY) { // otherwise "no"
set_temp_access(real_path, proc_info, SET_DENY);
free(real_path);
return 0;
}
free(real_path);
// deny on unknown options.
return 0; return 0;
} }

View File

@@ -12,10 +12,17 @@ else
if [[ $FAKE_ZENITY_RESPONSE == "yes_tmp" ]]; then if [[ $FAKE_ZENITY_RESPONSE == "yes_tmp" ]]; then
printf "Allow this time\n" printf "Allow this time\n"
exit 1 exit 1
elif [[ $FAKE_ZENITY_RESPONSE == "yes_tmp_alt" ]]; then
printf "Allow this time\n"
echo "yes_alt" >~/.fake_zenity_response
exit 1
elif [[ $FAKE_ZENITY_RESPONSE == "no" ]]; then elif [[ $FAKE_ZENITY_RESPONSE == "no" ]]; then
exit 1 exit 1
elif [[ $FAKE_ZENITY_RESPONSE == "yes" ]]; then elif [[ $FAKE_ZENITY_RESPONSE == "yes" ]]; then
exit 0 exit 0
elif [[ $FAKE_ZENITY_RESPONSE == "yes_alt" ]]; then
echo "yes_tmp_alt" >~/.fake_zenity_response
exit 0
fi fi
fi fi
fi fi

View File

@@ -25,10 +25,18 @@ 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 == "--perf" ]]; then
echo "Profiling with perf..."
../build/icfs -o default_permissions ./protected ./.pt.db &
echo "Profiling will require root privilieges."
sleep 3
echo "Attaching to $(pgrep icfs)"
sudo perf record -g -e cycles:u --call-graph dwarf -p $(pgrep icfs) &
sleep 10
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'."
valgrind -s ../build/icfs -o default_permissions ./protected ./.pt.db & valgrind --leak-check=full -s ../build/icfs -o default_permissions ./protected ./.pt.db &
sleep 5 sleep 5
fi fi
@@ -126,9 +134,29 @@ else
echo "[ICFS-TEST]: OK" echo "[ICFS-TEST]: OK"
fi fi
if [[ $1 == "--perf" ]]; then
zenity --set-fake-response yes_tmp
rm -rf ./protected/*
zenity --set-fake-response yes_alt
bonnie++ -p 4
bonnie++ -d ./protected -c 4 -r 256 -y s >/dev/null &
bonnie++ -d ./protected -c 4 -r 256 -y s >/dev/null &
bonnie++ -d ./protected -c 4 -r 256 -y s >/dev/null &
bonnie++ -d ./protected -c 4 -r 256 -y s >/dev/null
bonnie++ -p -1
fi
# unmount # unmount
sleep 0.5 sleep 0.5
#lsof +f -- $(realpath ./protected) #lsof +f -- $(realpath ./protected)
umount $(realpath ./protected) umount $(realpath ./protected)
sleep 0.5 sleep 0.5
if [[ $1 == "--perf" ]]; then
mv ./callgraph.png ./callgraph_old.png
real_user=$USER
sudo chown "$real_user" ./perf.data
perf script --dsos=icfs | gprof2dot -f perf | dot -Tpng -o callgraph.png
echo "Profile graph was written to \"callgraph.png\""
fi