blob: 342f9e644e41f2a499dfd7aaff23628405ee757d [file] [log] [blame]
/*
** Path sandbox for the gentoo linux portage package system, initially
** based on the ROCK Linux Wrapper for getting a list of created files
**
** to integrate with bash, bash should have been built like this
**
** ./configure --prefix=<prefix> --host=<host> --without-gnu-malloc
**
** it's very important that the --enable-static-link option is NOT specified
**
** Copyright (C) 2001 Geert Bevin, Uwyn, http://www.uwyn.com
** Distributed under the terms of the GNU General Public License, v2 or later
** Author : Geert Bevin <gbevin@uwyn.com>
** $Id: /var/cvsroot/gentoo-src/portage/src/sandbox/Attic/libsandbox.c,v 1.8 2002/08/05 05:51:39 drobbins Exp $
*/
#define _GNU_SOURCE
#define _REENTRANT
#define open xxx_open
#define open64 xxx_open64
# include <dirent.h>
# include <dlfcn.h>
# include <errno.h>
# include <fcntl.h>
# include <stdarg.h>
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <sys/file.h>
# include <sys/stat.h>
# include <sys/types.h>
# include <unistd.h>
# include <utime.h>
#undef open
#undef open64
#define PIDS_FILE "/tmp/sandboxpids.tmp"
typedef struct {
int show_access_violation;
char** deny_prefixes;
int num_deny_prefixes;
char** read_prefixes;
int num_read_prefixes;
char** write_prefixes;
int num_write_prefixes;
char** predict_prefixes;
int num_predict_prefixes;
char** write_denied_prefixes;
int num_write_denied_prefixes;
} sbcontext_t;
int check_access(sbcontext_t*, const char*, const char*);
int check_syscall(sbcontext_t*, const char*, const char*);
int before_syscall(const char*, const char*);
int before_syscall_open_int(const char*, const char*, int);
int before_syscall_open_char(const char*, const char*, const char*);
void clean_env_entries(char***, int*);
char* filter_path(const char*);
void* get_dl_symbol(char*);
void init_context(sbcontext_t*);
void init_env_entries(char***, int*, char*, int);
int is_sandbox_on();
int is_sandbox_pid();
/* Wrapper macros and functions */
/* macro definition to wrap functions before and after the
execution of basic file related system-calls.
nr : the argument number of the system-call's argument that
contains the file name to monitor
rt : the return type of the system call
name : the name of the function call
arg1, arg2, arg3 : the types of the function call's arguments
fl : the argument number of the system-call's argument that
contains the file access flags
md : the argument number of the system-call's argument that
contains the file access mode
*/
#define wrsysc3(nr, rt, name, arg1, arg2, arg3) \
\
/* the function call is defined externally from this file */ \
extern rt name(arg1, arg2, arg3); \
\
/* orig_ ## name is a pointer to a function with three arguments and the
return type of the system call. This will be used to store the pointer
to the system call function and call it. */ \
rt (*orig_ ## name)(arg1, arg2, arg3) = NULL; \
\
rt name(arg1 a1, arg2 a2, arg3 a3) \
{ \
rt result = -1; \
int old_errno = errno; \
if (0 == is_sandbox_on() || 1 == before_syscall(#name, a ## nr)) \
{ \
if (!orig_ ## name) \
{ \
orig_ ## name = get_dl_symbol(#name); \
} \
errno = old_errno; \
result = orig_ ## name(a1, a2, a3); \
} \
return result; \
}
#define wrsysc2(nr, rt, name, arg1, arg2) \
extern rt name(arg1, arg2); \
rt (*orig_ ## name)(arg1, arg2) = NULL; \
\
rt name(arg1 a1, arg2 a2) \
{ \
rt result = -1; \
int old_errno = errno; \
if (0 == is_sandbox_on() || 1 == before_syscall(#name, a ## nr)) \
{ \
if (!orig_ ## name) \
{ \
orig_ ## name = get_dl_symbol(#name); \
} \
errno = old_errno; \
result = orig_ ## name(a1, a2); \
} \
return result; \
}
#define wrsysc1(nr, rt, name, arg1) \
extern rt name(arg1); \
rt (*orig_ ## name)(arg1) = NULL; \
\
rt name(arg1 a1) \
{ \
rt result = -1; \
int old_errno = errno; \
if (0 == is_sandbox_on() || 1 == before_syscall(#name, a ## nr)) \
{ \
if (!orig_ ## name) \
{ \
orig_ ## name = get_dl_symbol(#name); \
} \
errno = old_errno; \
result = orig_ ## name(a1); \
} \
return result; \
}
#define wrsysc1ptr(nr, rt, name, arg1) \
extern rt name(arg1); \
rt (*orig_ ## name)(arg1) = NULL; \
\
rt name(arg1 a1) \
{ \
rt result = NULL; \
int old_errno = errno; \
if (0 == is_sandbox_on() || 1 == before_syscall(#name, a ## nr)) \
{ \
if (!orig_ ## name) \
{ \
orig_ ## name = get_dl_symbol(#name); \
} \
errno = old_errno; \
result = orig_ ## name(a1); \
} \
return result; \
}
#define wropenint3(nr, fl, rt, name, arg1, arg2, arg3) \
extern rt name(arg1, arg2, arg3); \
rt (*orig_ ## name)(arg1, arg2, arg3) = NULL; \
\
rt name(arg1 a1, arg2 a2, arg3 a3) \
{ \
rt result = -1; \
int old_errno = errno; \
if (0 == is_sandbox_on() || \
1 == before_syscall_open_int(#name, a ## nr, a ## fl)) \
{ \
if (!orig_ ## name) \
{ \
orig_ ## name = get_dl_symbol(#name); \
} \
errno = old_errno; \
result = orig_ ## name(a1, a2, a3); \
} \
return result; \
}
#define wropenchar2(nr, md, rt, name, arg1, arg2) \
extern rt name(arg1, arg2); \
rt (*orig_ ## name)(arg1, arg2) = NULL; \
\
rt name(arg1 a1, arg2 a2) \
{ \
rt result = NULL; \
int old_errno = errno; \
if (0 == is_sandbox_on() || \
1 == before_syscall_open_char(#name, a ## nr, a ## md)) \
{ \
if (!orig_ ## name) \
{ \
orig_ ## name = get_dl_symbol(#name); \
} \
errno = old_errno; \
result = orig_ ## name(a1, a2); \
} \
return result; \
}
#define wropenchar3(nr, md, rt, name, arg1, arg2, arg3) \
extern rt name(arg1, arg2, arg3); \
rt (*orig_ ## name)(arg1, arg2, arg3) = NULL; \
\
rt name(arg1 a1, arg2 a2, arg3 a3) \
{ \
rt result = NULL; \
int old_errno = errno; \
if (0 == is_sandbox_on() || \
1 == before_syscall_open_char(#name, a ## nr, a ## md)) \
{ \
if (!orig_ ## name) \
{ \
orig_ ## name = get_dl_symbol(#name); \
} \
errno = old_errno; \
result = orig_ ## name(a1, a2, a3); \
} \
return result; \
}
#define wrexec3(nr, rt, name, arg1, arg2, arg3) \
extern rt name(arg1, arg2, arg3); \
rt (*orig_ ## name)(arg1, arg2, arg3) = NULL; \
\
rt name(arg1 a1, arg2 a2, arg3 a3) \
{ \
rt result = -1; \
int old_errno = errno; \
if (0 == is_sandbox_on() || 1 == before_syscall(#name, a ## nr)) \
{ \
if (!orig_ ## name) \
{ \
orig_ ## name = get_dl_symbol(#name); \
} \
errno = old_errno; \
result = orig_ ## name(a1, a2, a3); \
} \
return result; \
}
#define wrexec2(nr, rt, name, arg1, arg2) \
extern rt name(arg1, arg2); \
rt (*orig_ ## name)(arg1, arg2) = NULL; \
\
rt name(arg1 a1, arg2 a2) \
{ \
rt result = -1; \
int old_errno = errno; \
if (0 == is_sandbox_on() || 1 == before_syscall(#name, a ## nr)) \
{ \
if (!orig_ ## name) \
{ \
orig_ ## name = get_dl_symbol(#name); \
} \
errno = old_errno; \
result = orig_ ## name(a1, a2); \
} \
return result; \
}
#define wrexec2va(nr, rt, name, arg1, arg2) \
extern rt name(arg1, arg2, ...); \
rt (*orig_ ## name)(arg1, arg2, ...) = NULL; \
\
rt name(arg1 a1, arg2 a2, ...) \
{ \
void* result = NULL; \
int old_errno = errno; \
if (0 == is_sandbox_on() || 1 == before_syscall(#name, a ## nr)) \
{ \
if (!orig_ ## name) \
{ \
orig_ ## name = get_dl_symbol(#name); \
} \
errno = old_errno; \
result = __builtin_apply( (void(*)()) orig_ ## name, \
__builtin_apply_args(), 32 ); \
old_errno = errno; \
} \
if (NULL == result) \
{ \
return -1; \
} \
else \
{ \
__builtin_return(result); \
} \
}
wropenint3(1, 2, int, open, const char*, int, mode_t)
wropenint3(1, 2, int, open64, const char*, int, mode_t)
wropenchar2(1, 2, FILE*, fopen, const char*, const char*)
wropenchar2(1, 2, FILE*, fopen64, const char*, const char*)
wropenchar3(1, 2, FILE*, freopen, const char*, const char*, FILE*)
wropenchar2(1, 2, FILE*, popen, const char*, const char*)
// write syscalls
wrsysc2(1, int, creat, const char*, mode_t)
wrsysc2(1, int, creat64, const char*, mode_t)
wrsysc2(1, int, mkdir, const char*, mode_t)
wrsysc3(1, int, mknod, const char*, mode_t, dev_t)
wrsysc2(1, int, mkfifo, const char*, mode_t)
wrsysc2(2, int, link, const char*, const char*)
wrsysc2(2, int, symlink, const char*, const char*)
wrsysc2(2, int, rename, const char*, const char*)
wrsysc2(1, int, utime, const char*, const struct utimbuf*)
wrsysc2(1, int, utimes, const char*, struct timeval*)
wrsysc1(1, int, unlink, const char*)
wrsysc1(1, int, rmdir, const char*)
wrsysc3(1, int, chown, const char*, uid_t, gid_t)
wrsysc3(1, int, lchown, const char*, uid_t, gid_t)
wrsysc2(1, int, chmod, const char*, mode_t)
/* read syscalls */
wrsysc1ptr(1, DIR*, opendir, const char*)
/* execution syscalls */
wrsysc1(1, int, system, const char*)
wrexec2va(1, int, execl, const char*, const char*)
wrexec2va(1, int, execle, const char*, const char*)
wrexec2(1, int, execv, const char*, char* const*)
wrexec3(1, int, execve, const char*, char* const*, char* const*)
/* execlp is redirected to execvp */
/* execvp is special since it should search the PATH var entries */
extern int execvp(const char*, char* const*);
int(*orig_execvp)(const char*, char* const*) = NULL;
int execvp(const char* file, char* const* argv)
{
int result = -1;
int old_errno = errno;
int i = 0;
int allowed = 1;
char** path_entries = NULL;
int num_path_entries = 0;
char constructed_path[255];
if (1 == is_sandbox_on())
{
init_env_entries(&path_entries, &num_path_entries, "PATH", 0);
for (i = 0; i < num_path_entries; i++)
{
strcpy(constructed_path, path_entries[i]);
strcat(constructed_path, "/");
strcat(constructed_path, file);
if (0 == before_syscall("execvp", constructed_path))
{
allowed = 0;
break;
}
}
clean_env_entries(&path_entries, &num_path_entries);
}
if (1 == allowed)
{
if (!orig_execvp)
{
orig_execvp = get_dl_symbol("execvp");
}
errno = old_errno;
result = orig_execvp(file, argv);
old_errno = errno;
}
errno = old_errno;
return result;
}
/* lseek, lseek64, fdopen, fchown, fchmod, fcntl, lockf
are not wrapped since they can't be used if open is wrapped correctly
and unaccessible file descriptors are not possible to create */
void* get_dl_symbol(char* symname)
{
void* result = dlsym(RTLD_NEXT, symname);
if (0 == result)
{
fprintf(stderr, "Sandbox : can't resolve %s: %s.\n", symname, dlerror());
abort();
}
return result;
}
void init_context(sbcontext_t* context)
{
context->show_access_violation = 1;
context->deny_prefixes = NULL;
context->num_deny_prefixes = 0;
context->read_prefixes = NULL;
context->num_read_prefixes = 0;
context->write_prefixes = NULL;
context->num_write_prefixes = 0;
context->predict_prefixes = NULL;
context->num_predict_prefixes = 0;
context->write_denied_prefixes = NULL;
context->num_write_denied_prefixes = 0;
}
int is_sandbox_pid()
{
int result = 0;
FILE* pids_stream = NULL;
int pids_file = -1;
int current_pid = 0;
int tmp_pid = 0;
pids_stream = fopen(PIDS_FILE, "r");
if (NULL == pids_stream)
{
perror(">>> pids file fopen");
}
else
{
pids_file = fileno(pids_stream);
if (pids_file < 0)
{
perror(">>> pids file fileno");
}
else
{
current_pid = getpid();
while (EOF != fscanf(pids_stream, "%d\n", &tmp_pid))
{
if (tmp_pid == current_pid)
{
result = 1;
break;
}
}
}
if (EOF == fclose(pids_stream))
{
perror(">>> pids file fclose");
}
pids_stream = NULL;
pids_file = -1;
}
return result;
}
void clean_env_entries(char*** prefixes_array, int* prefixes_num)
{
int i = 0;
if (NULL != *prefixes_array)
{
for (i = 0; i < *prefixes_num; i++)
{
if (NULL != (*prefixes_array)[i])
{
free((*prefixes_array)[i]);
(*prefixes_array)[i] = NULL;
}
}
free(*prefixes_array);
*prefixes_array = NULL;
*prefixes_num = 0;
}
}
void init_env_entries(char*** prefixes_array, int* prefixes_num, char* env, int warn)
{
char* prefixes_env = getenv(env);
if (NULL == prefixes_env)
{
fprintf(stderr, "Sandbox error : the %s environmental variable should be defined.\n", env);
}
else
{
char* buffer = NULL;
int prefixes_env_length = strlen(prefixes_env);
int i = 0;
int num_delimiters = 0;
char* token = NULL;
char* prefix = NULL;
for (i = 0; i < prefixes_env_length; i++)
{
if (':' == prefixes_env[i])
{
num_delimiters++;
}
}
if (num_delimiters > 0)
{
buffer = (char*)malloc(sizeof(char)*(prefixes_env_length+1));
*prefixes_array = (char**)malloc(sizeof(char*)*(num_delimiters+1));
strcpy(buffer, prefixes_env);
token = strtok(buffer, ":");
while (NULL != token &&
strlen(token) > 0)
{
prefix = (char*)malloc(sizeof(char)*(strlen(token)+1));
strcpy(prefix, token);
(*prefixes_array)[(*prefixes_num)++] = filter_path(prefix);
free(prefix);
token = strtok(NULL, ":");
}
free(buffer);
buffer = NULL;
}
else if(prefixes_env_length > 0)
{
(*prefixes_array) = (char**)malloc(sizeof(char*));
prefix = (char*)malloc(sizeof(char)*(prefixes_env_length+1));
strcpy(prefix, prefixes_env);
(*prefixes_array)[(*prefixes_num)++] = filter_path(prefix);
free(prefix);
}
}
}
char* filter_path(const char* path)
{
int initial_path_length = strlen(path);
char* filtered_path = (char*)malloc(sizeof(char)*(initial_path_length+1));
int i = 0;
int j = 0;
for (i = 0, j = 0; i < initial_path_length;)
{
filtered_path[j] = path[i];
if ('/' == filtered_path[j])
{
while ('/' == path[i] &&
i < initial_path_length)
{
i++;
}
}
else
{
i++;
}
j++;
}
filtered_path[j] = 0;
return filtered_path;
}
int check_access(sbcontext_t* sbcontext, const char* func, const char* path)
{
int result = -1;
int i = 0;
char* filtered_path = filter_path(path);
if ('/' != path[0])
{
return 0;
}
if (0 == strcmp(filtered_path, "/etc/ld.so.preload") &&
is_sandbox_pid())
{
result = 1;
}
if (-1 == result)
{
if (NULL != sbcontext->deny_prefixes)
{
for (i = 0; i < sbcontext->num_deny_prefixes; i++)
{
if (0 == strncmp(filtered_path, sbcontext->deny_prefixes[i], strlen(sbcontext->deny_prefixes[i])))
{
result = 0;
break;
}
}
}
if (-1 == result)
{
if (NULL != sbcontext->read_prefixes &&
(0 == strcmp(func, "open_rd") ||
0 == strcmp(func, "popen") ||
0 == strcmp(func, "opendir") ||
0 == strcmp(func, "system") ||
0 == strcmp(func, "execl") ||
0 == strcmp(func, "execlp") ||
0 == strcmp(func, "execle") ||
0 == strcmp(func, "execv") ||
0 == strcmp(func, "execvp") ||
0 == strcmp(func, "execve")))
{
for (i = 0; i < sbcontext->num_read_prefixes; i++)
{
if (0 == strncmp(filtered_path, sbcontext->read_prefixes[i], strlen(sbcontext->read_prefixes[i])))
{
result = 1;
break;
}
}
}
else if (NULL != sbcontext->write_prefixes &&
(0 == strcmp(func, "open_wr") ||
0 == strcmp(func, "creat") ||
0 == strcmp(func, "creat64") ||
0 == strcmp(func, "mkdir") ||
0 == strcmp(func, "mknod") ||
0 == strcmp(func, "mkfifo") ||
0 == strcmp(func, "link") ||
0 == strcmp(func, "symlink") ||
0 == strcmp(func, "rename") ||
0 == strcmp(func, "utime") ||
0 == strcmp(func, "utimes") ||
0 == strcmp(func, "unlink") ||
0 == strcmp(func, "rmdir") ||
0 == strcmp(func, "chown") ||
0 == strcmp(func, "lchown") ||
0 == strcmp(func, "chmod")))
{
struct stat tmp_stat;
for (i = 0; i < sbcontext->num_write_denied_prefixes; i++)
{
if (0 == strncmp(filtered_path, sbcontext->write_denied_prefixes[i], strlen(sbcontext->write_denied_prefixes[i])))
{
result = 0;
break;
}
}
if (-1 == result)
{
for (i = 0; i < sbcontext->num_write_prefixes; i++)
{
if (0 == strncmp(filtered_path, sbcontext->write_prefixes[i], strlen(sbcontext->write_prefixes[i])))
{
result = 1;
break;
}
}
if (-1 == result)
{
/* hack to prevent mkdir of existing dirs to show errors */
if (strcmp(func, "mkdir") == 0)
{
if (0 == stat(filtered_path, &tmp_stat))
{
sbcontext->show_access_violation = 0;
result = 0;
}
}
if (-1 == result)
{
for (i = 0; i < sbcontext->num_predict_prefixes; i++)
{
if (0 == strncmp(filtered_path, sbcontext->predict_prefixes[i], strlen(sbcontext->predict_prefixes[i])))
{
sbcontext->show_access_violation = 0;
result = 0;
break;
}
}
}
}
}
}
}
}
if (-1 == result)
{
result = 0;
}
free(filtered_path);
return result;
}
int check_syscall(sbcontext_t* sbcontext, const char* func, const char* file)
{
int result = 1;
char* absolute_path = NULL;
char* tmp_buffer = NULL;
struct stat log_stat;
char* log_path = NULL;
int log_file = 0;
struct stat debug_log_stat;
char* debug_log_env = NULL;
char* debug_log_path = NULL;
int debug_log_file = 0;
char buffer[512];
if ('/' == file[0])
{
absolute_path = (char*)malloc(sizeof(char)*(strlen(file)+1));
sprintf(absolute_path, "%s", file);
}
else
{
tmp_buffer = get_current_dir_name();
absolute_path = (char*)malloc(sizeof(char)*(strlen(tmp_buffer)+1+strlen(file)+1));
sprintf(absolute_path,"%s/%s", tmp_buffer, file);
free(tmp_buffer);
tmp_buffer = NULL;
}
log_path = getenv("SANDBOX_LOG");
debug_log_env = getenv("SANDBOX_DEBUG");
debug_log_path = getenv("SANDBOX_DEBUG_LOG");
if ((NULL == log_path || 0 != strcmp(absolute_path, log_path)) &&
(NULL == debug_log_env || NULL == debug_log_path || 0 != strcmp(absolute_path, debug_log_path)) &&
0 == check_access(sbcontext, func, absolute_path))
{
if (1 == sbcontext->show_access_violation)
{
fprintf(stderr, "\e[31;01mACCESS DENIED\033[0m %s:%*s%s\n", func, (int)(10-strlen(func)), "", absolute_path);
if (NULL != log_path)
{
sprintf(buffer, "%s:%*s%s\n", func, (int)(10-strlen(func)), "", absolute_path);
if (0 == lstat(log_path, &log_stat) &&
0 == S_ISREG(log_stat.st_mode))
{
fprintf(stderr, "\e[31;01mSECURITY BREACH\033[0m %s already exists and is not a regular file.\n", log_path);
}
else
{
log_file = open(log_path, O_APPEND|O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
if(log_file >= 0)
{
write(log_file, buffer, strlen(buffer));
close(log_file);
}
}
}
}
result = 0;
}
else if (NULL != debug_log_env)
{
if (NULL != debug_log_path)
{
if (0 != strcmp(absolute_path, debug_log_path))
{
sprintf(buffer, "%s:%*s%s\n", func, (int)(10-strlen(func)), "", absolute_path);
if (0 == lstat(debug_log_path, &debug_log_stat) &&
0 == S_ISREG(debug_log_stat.st_mode))
{
fprintf(stderr, "\e[31;01mSECURITY BREACH\033[0m %s already exists and is not a regular file.\n", log_path);
}
else
{
debug_log_file = open(debug_log_path, O_APPEND|O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
if(debug_log_file >= 0)
{
write(debug_log_file, buffer, strlen(buffer));
close(debug_log_file);
}
}
}
}
else
{
fprintf(stderr, "\e[32;01mACCESS ALLOWED\033[0m %s:%*s%s\n", func, (int)(10-strlen(func)), "", absolute_path);
}
}
free(absolute_path);
absolute_path = NULL;
return result;
}
int is_sandbox_on()
{
/* $SANDBOX_ACTIVE is an env variable that should ONLY
* be used internal by sandbox.c and libsanbox.c. External
* sources should NEVER set it, else the sandbox is enabled
* in some cases when run in parallel with another sandbox,
* but not even in the sandbox shell.
*
* Azarah (3 Aug 2002)
*/
if (NULL != getenv("SANDBOX_ON") &&
0 == strcmp(getenv("SANDBOX_ON"), "1") &&
NULL != getenv("SANDBOX_ACTIVE") &&
0 == strcmp(getenv("SANDBOX_ACTIVE"), "armedandready"))
{
return 1;
}
else
{
return 0;
}
}
int before_syscall(const char* func, const char* file)
{
int result = 1;
sbcontext_t sbcontext;
init_context(&sbcontext);
init_env_entries(&(sbcontext.deny_prefixes), &(sbcontext.num_deny_prefixes), "SANDBOX_DENY", 1);
init_env_entries(&(sbcontext.read_prefixes), &(sbcontext.num_read_prefixes), "SANDBOX_READ", 1);
init_env_entries(&(sbcontext.write_prefixes), &(sbcontext.num_write_prefixes), "SANDBOX_WRITE", 1);
init_env_entries(&(sbcontext.predict_prefixes), &(sbcontext.num_predict_prefixes), "SANDBOX_PREDICT", 1);
result = check_syscall(&sbcontext, func, file);
clean_env_entries(&(sbcontext.deny_prefixes), &(sbcontext.num_deny_prefixes));
clean_env_entries(&(sbcontext.read_prefixes), &(sbcontext.num_read_prefixes));
clean_env_entries(&(sbcontext.write_prefixes), &(sbcontext.num_write_prefixes));
clean_env_entries(&(sbcontext.predict_prefixes), &(sbcontext.num_predict_prefixes));
if (0 == result)
{
errno = EACCES;
}
return result;
}
int before_syscall_open_int(const char* func, const char* file, int flags)
{
if (flags & O_WRONLY ||
flags & O_RDWR)
{
return before_syscall("open_wr", file);
}
else
{
return before_syscall("open_rd", file);
}
}
int before_syscall_open_char(const char* func, const char* file, const char* mode)
{
if (strcmp(mode, "r") == 0 ||
strcmp(mode, "rb") == 0)
{
return before_syscall("open_rd", file);
}
else
{
return before_syscall("open_wr", file);
}
}