major cleanup

This commit is contained in:
netblue30 2016-10-30 15:54:05 -04:00
parent 2ef5a3dc71
commit f898290fd7
30 changed files with 869 additions and 889 deletions

1
.gitignore vendored
View file

@ -19,4 +19,5 @@ src/ftee/ftee
src/tags
src/faudit/faudit
src/fnet/fnet
src/fseccomp/fseccomp
uids.h

2
README
View file

@ -86,6 +86,8 @@ valoq (https://github.com/valoq)
- added support for /srv in --whitelist feature
- Eye of GNOME and Evolution profiles
- blacklist suid binaries in disable-common.inc
Vadim A. Misbakh-Soloviov (https://github.com/msva)
- profile fixes
Rafael Cavalcanti (https://github.com/rccavalcanti)
- chromium profile fixes for Arch Linux
Deelvesh Bunjun (https://github.com/DeelveshBunjun)

View file

@ -60,11 +60,6 @@ void appimage_set(const char *appimage_path) {
exit(1);
}
// populate /run/firejail directory
EUID_ROOT();
fs_build_firejail_dir();
EUID_USER();
// find or allocate a free loop device to use
EUID_ROOT();
int cfd = open("/dev/loop-control", O_RDWR);

View file

@ -40,6 +40,7 @@ typedef struct arp_hdr_t {
uint8_t target_ip[4];
} ArpHdr;
// returns 0 if the address is not in use, -1 otherwise
int arp_check(const char *dev, uint32_t destaddr, uint32_t srcaddr) {
if (strlen(dev) > IFNAMSIZ) {
@ -286,189 +287,4 @@ uint32_t arp_assign(const char *dev, Bridge *br) {
return ip;
}
// scan interface (--scan option)
void arp_scan(const char *dev, uint32_t ifip, uint32_t ifmask) {
assert(dev);
assert(ifip);
// printf("Scanning interface %s (%d.%d.%d.%d/%d)\n",
// dev, PRINT_IP(ifip & ifmask), mask2bits(ifmask));
if (strlen(dev) > IFNAMSIZ) {
fprintf(stderr, "Error: invalid network device name %s\n", dev);
exit(1);
}
// find interface mac address
int sock;
if ((sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
errExit("socket");
struct ifreq ifr;
memset(&ifr, 0, sizeof (ifr));
strncpy(ifr.ifr_name, dev, IFNAMSIZ);
if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0)
errExit("ioctl");
close(sock);
uint8_t mac[6];
memcpy (mac, ifr.ifr_hwaddr.sa_data, 6);
// open layer2 socket
if ((sock = socket(PF_PACKET, SOCK_RAW, htons (ETH_P_ALL))) < 0)
errExit("socket");
// try all possible ip addresses in ascending order
uint32_t range = ~ifmask + 1; // the number of potential addresses
// this software is not supported for /31 networks
if (range < 4) {
fprintf(stderr, "Warning: this option is not supported for /31 networks\n");
close(sock);
return;
}
uint32_t dest = (ifip & ifmask) + 1;
uint32_t last = dest + range - 1;
uint32_t src = htonl(ifip);
// wait not more than one second for an answer
int header_printed = 0;
uint32_t last_ip = 0;
struct timeval ts;
ts.tv_sec = 2; // 2 seconds receive timeout
ts.tv_usec = 0;
while (1) {
fd_set rfds;
FD_ZERO(&rfds);
FD_SET(sock, &rfds);
fd_set wfds;
FD_ZERO(&wfds);
FD_SET(sock, &wfds);
int maxfd = sock;
uint8_t frame[ETH_FRAME_LEN]; // includes eht header, vlan, and crc
memset(frame, 0, ETH_FRAME_LEN);
int nready;
if (dest < last)
nready = select(maxfd + 1, &rfds, &wfds, (fd_set *) 0, NULL);
else
nready = select(maxfd + 1, &rfds, (fd_set *) 0, (fd_set *) 0, &ts);
if (nready < 0)
errExit("select");
if (nready == 0) { // timeout
break;
}
if (FD_ISSET(sock, &wfds) && dest < last) {
// configure layer2 socket address information
struct sockaddr_ll addr;
memset(&addr, 0, sizeof(addr));
if ((addr.sll_ifindex = if_nametoindex(dev)) == 0)
errExit("if_nametoindex");
addr.sll_family = AF_PACKET;
memcpy (addr.sll_addr, mac, 6);
addr.sll_halen = htons(6);
// build the arp packet header
ArpHdr hdr;
memset(&hdr, 0, sizeof(hdr));
hdr.htype = htons(1);
hdr.ptype = htons(ETH_P_IP);
hdr.hlen = 6;
hdr.plen = 4;
hdr.opcode = htons(1); //ARPOP_REQUEST
memcpy(hdr.sender_mac, mac, 6);
memcpy(hdr.sender_ip, (uint8_t *)&src, 4);
uint32_t dst = htonl(dest);
memcpy(hdr.target_ip, (uint8_t *)&dst, 4);
// build ethernet frame
uint8_t frame[ETH_FRAME_LEN]; // includes eht header, vlan, and crc
memset(frame, 0, sizeof(frame));
frame[0] = frame[1] = frame[2] = frame[3] = frame[4] = frame[5] = 0xff;
memcpy(frame + 6, mac, 6);
frame[12] = ETH_P_ARP / 256;
frame[13] = ETH_P_ARP % 256;
memcpy (frame + 14, &hdr, sizeof(hdr));
// send packet
int len;
if ((len = sendto (sock, frame, 14 + sizeof(ArpHdr), 0, (struct sockaddr *) &addr, sizeof (addr))) <= 0)
errExit("send");
//printf("send %d bytes to %d.%d.%d.%d\n", len, PRINT_IP(dest));
fflush(0);
dest++;
}
if (FD_ISSET(sock, &rfds)) {
// read the incoming packet
int len = recvfrom(sock, frame, ETH_FRAME_LEN, 0, NULL, NULL);
if (len < 0) {
perror("recvfrom");
}
// parse the incoming packet
if ((unsigned int) len < 14 + sizeof(ArpHdr))
continue;
// look only at ARP packets
if (frame[12] != (ETH_P_ARP / 256) || frame[13] != (ETH_P_ARP % 256))
continue;
ArpHdr hdr;
memcpy(&hdr, frame + 14, sizeof(ArpHdr));
if (hdr.opcode == htons(2)) {
// check my mac and my address
if (memcmp(mac, hdr.target_mac, 6) != 0)
continue;
uint32_t ip;
memcpy(&ip, hdr.target_ip, 4);
if (ip != src)
continue;
memcpy(&ip, hdr.sender_ip, 4);
ip = ntohl(ip);
if (ip == last_ip) // filter duplicates
continue;
last_ip = ip;
// printing
if (header_printed == 0) {
printf(" Network scan:\n");
// print parent interface
if (cfg.bridge0.configured && cfg.bridge0.ip && cfg.bridge0.macvlan &&
(cfg.bridge0.ip & cfg.bridge0.mask) == (ifip & cfg.bridge0.mask))
printf(" %02x:%02x:%02x:%02x:%02x:%02x\t%d.%d.%d.%d\n",
PRINT_MAC(cfg.bridge0.mac), PRINT_IP(cfg.bridge0.ip));
if (cfg.bridge1.configured && cfg.bridge1.ip && cfg.bridge1.macvlan &&
(cfg.bridge1.ip & cfg.bridge1.mask) == (ifip & cfg.bridge1.mask))
printf(" %02x:%02x:%02x:%02x:%02x:%02x\t%d.%d.%d.%d\n",
PRINT_MAC(cfg.bridge1.mac), PRINT_IP(cfg.bridge1.ip));
if (cfg.bridge2.configured && cfg.bridge2.ip && cfg.bridge2.macvlan &&
(cfg.bridge2.ip & cfg.bridge2.mask) == (ifip & cfg.bridge2.mask))
printf(" %02x:%02x:%02x:%02x:%02x:%02x\t%d.%d.%d.%d\n",
PRINT_MAC(cfg.bridge2.mac), PRINT_IP(cfg.bridge2.ip));
if (cfg.bridge3.configured && cfg.bridge3.ip && cfg.bridge3.macvlan &&
(cfg.bridge3.ip & cfg.bridge3.mask) == (ifip & cfg.bridge3.mask))
printf(" %02x:%02x:%02x:%02x:%02x:%02x\t%d.%d.%d.%d\n",
PRINT_MAC(cfg.bridge3.mac), PRINT_IP(cfg.bridge3.ip));
header_printed = 1;
}
printf(" %02x:%02x:%02x:%02x:%02x:%02x\t%d.%d.%d.%d\n",
PRINT_MAC(hdr.sender_mac), PRINT_IP(ip));
}
}
}
close(sock);
}

View file

@ -363,20 +363,19 @@ void net_if_ip(const char *ifname, uint32_t ip, uint32_t mask, int mtu);
void net_if_ip6(const char *ifname, const char *addr6);
int net_get_if_addr(const char *bridge, uint32_t *ip, uint32_t *mask, uint8_t mac[6], int *mtu);
int net_add_route(uint32_t dest, uint32_t mask, uint32_t gw);
void net_ifprint(void);
uint32_t network_get_defaultgw(void);
int net_config_mac(const char *ifname, const unsigned char mac[6]);
int net_get_mac(const char *ifname, unsigned char mac[6]);
void net_config_interface(const char *dev, uint32_t ip, uint32_t mask, int mtu);
// preproc.c
void preproc_build_firejail_dir(void);
void preproc_mount_mnt_dir(void);
void preproc_build_cp_command(void);
void preproc_delete_cp_command(void) ;
void preproc_remount_mnt_dir(void);
// fs.c
// build /run/firejail directory
void fs_build_firejail_dir(void);
// build /run/firejail/mnt directory
void fs_build_mnt_dir(void);
// grab a copy of cp command
void fs_build_cp_command(void);
// delete the temporary cp command
void fs_delete_cp_command(void) ;
// blacklist files or directoies by mounting empty files on top of them
void fs_blacklist(void);
// remount a directory read-only
@ -393,7 +392,6 @@ void fs_overlayfs(void);
// chroot into an existing directory; mount exiting /dev and update /etc/resolv.conf
void fs_chroot(const char *rootdir);
int fs_check_chroot_dir(const char *rootdir);
void fs_private_tmp(void);
// profile.c
// find and read the profile specified by name from dir directory
@ -430,8 +428,6 @@ int restricted_shell(const char *user);
int arp_check(const char *dev, uint32_t destaddr, uint32_t srcaddr);
// assign an IP address using arp scanning
uint32_t arp_assign(const char *dev, Bridge *br);
// scan interface (--scan option)
void arp_scan(const char *dev, uint32_t srcaddr, uint32_t srcmask);
// util.c
void drop_privs(int nogroups);
@ -459,6 +455,8 @@ void invalid_filename(const char *fname);
uid_t get_group_id(const char *group);
int remove_directory(const char *path);
void flush_stdin(void);
void create_empty_dir_as_root(const char *dir, mode_t mode);
void create_empty_file_as_root(const char *dir, mode_t mode);
// fs_var.c
void fs_var_log(void); // mounting /var/log
@ -687,10 +685,11 @@ void build_cmdline(char **command_line, char **window_title, int argc, char **ar
#define PATH_FIREMON (PREFIX "/bin/firemon")
#define PATH_FSECCOMP (LIBDIR "/firejail/fseccomp")
// bitmapped filters for sbox_run
#define SBOX_ROOT 1
#define SBOX_USER 2
#define SBOX_CAPS 4
#define SBOX_SECCOMP 8
#define SBOX_ROOT (1 << 0)
#define SBOX_USER (1 << 1)
#define SBOX_SECCOMP (1 << 2)
#define SBOX_CAPS_NONE (1 << 3) // drop all capabilities
#define SBOX_CAPS_NETWORK (1 << 4) // caps filter for programs running network programs
// run sbox
int sbox_run(unsigned filter, int num, ...);

View file

@ -29,154 +29,7 @@
static void fs_rdwr(const char *dir);
static void create_dir_as_root(const char *dir, mode_t mode) {
assert(dir);
if (arg_debug)
printf("Creating %s directory\n", dir);
if (mkdir(dir, mode) == -1)
errExit("mkdir");
if (chmod(dir, mode) == -1)
errExit("chmod");
ASSERT_PERMS(dir, 0, 0, mode);
}
static void create_empty_dir(void) {
struct stat s;
if (stat(RUN_RO_DIR, &s)) {
/* coverity[toctou] */
if (mkdir(RUN_RO_DIR, S_IRUSR | S_IXUSR) == -1)
errExit("mkdir");
if (chmod(RUN_RO_DIR, S_IRUSR | S_IXUSR) == -1)
errExit("chmod");
ASSERT_PERMS(RUN_RO_DIR, 0, 0, S_IRUSR | S_IXUSR);
}
}
static void create_empty_file(void) {
struct stat s;
if (stat(RUN_RO_FILE, &s)) {
/* coverity[toctou] */
FILE *fp = fopen(RUN_RO_FILE, "w");
if (!fp)
errExit("fopen");
SET_PERMS_STREAM(fp, 0, 0, S_IRUSR);
fclose(fp);
}
}
// build /run/firejail directory
void fs_build_firejail_dir(void) {
struct stat s;
// CentOS 6 doesn't have /run directory
if (stat(RUN_FIREJAIL_BASEDIR, &s)) {
create_dir_as_root(RUN_FIREJAIL_BASEDIR, 0755);
}
// check /run/firejail directory belongs to root end exit if doesn't!
if (stat(RUN_FIREJAIL_DIR, &s) == 0) {
if (s.st_uid != 0 || s.st_gid != 0) {
fprintf(stderr, "Error: non-root %s directory, exiting...\n", RUN_FIREJAIL_DIR);
exit(1);
}
}
else {
create_dir_as_root(RUN_FIREJAIL_DIR, 0755);
}
if (stat(RUN_FIREJAIL_NETWORK_DIR, &s)) {
create_dir_as_root(RUN_FIREJAIL_NETWORK_DIR, 0755);
}
if (stat(RUN_FIREJAIL_BANDWIDTH_DIR, &s)) {
create_dir_as_root(RUN_FIREJAIL_BANDWIDTH_DIR, 0755);
}
if (stat(RUN_FIREJAIL_NAME_DIR, &s)) {
create_dir_as_root(RUN_FIREJAIL_NAME_DIR, 0755);
}
if (stat(RUN_FIREJAIL_X11_DIR, &s)) {
create_dir_as_root(RUN_FIREJAIL_X11_DIR, 0755);
}
if (stat(RUN_FIREJAIL_APPIMAGE_DIR, &s)) {
create_dir_as_root(RUN_FIREJAIL_APPIMAGE_DIR, 0755);
}
create_empty_dir();
create_empty_file();
}
// build /run/firejail/mnt directory
static int tmpfs_mounted = 0;
#ifdef HAVE_CHROOT
static void fs_build_remount_mnt_dir(void) {
tmpfs_mounted = 0;
fs_build_mnt_dir();
}
#endif
void fs_build_mnt_dir(void) {
struct stat s;
fs_build_firejail_dir();
// create /run/firejail/mnt directory
if (stat(RUN_MNT_DIR, &s)) {
create_dir_as_root(RUN_MNT_DIR, 0755);
}
// ... and mount tmpfs on top of it
if (!tmpfs_mounted) {
// mount tmpfs on top of /run/firejail/mnt
if (arg_debug)
printf("Mounting tmpfs on %s directory\n", RUN_MNT_DIR);
if (mount("tmpfs", RUN_MNT_DIR, "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0)
errExit("mounting /run/firejail/mnt");
tmpfs_mounted = 1;
fs_logger2("tmpfs", RUN_MNT_DIR);
}
}
// grab a copy of cp command
void fs_build_cp_command(void) {
struct stat s;
fs_build_mnt_dir();
if (stat(RUN_CP_COMMAND, &s)) {
char* fname = realpath("/bin/cp", NULL);
if (fname == NULL) {
fprintf(stderr, "Error: /bin/cp not found\n");
exit(1);
}
if (stat(fname, &s)) {
fprintf(stderr, "Error: /bin/cp not found\n");
exit(1);
}
if (is_link(fname)) {
fprintf(stderr, "Error: invalid /bin/cp file\n");
exit(1);
}
int rv = copy_file(fname, RUN_CP_COMMAND, 0, 0, 0755);
if (rv) {
fprintf(stderr, "Error: cannot access /bin/cp\n");
exit(1);
}
ASSERT_PERMS(RUN_CP_COMMAND, 0, 0, 0755);
free(fname);
}
}
// delete the temporary cp command
void fs_delete_cp_command(void) {
unlink(RUN_CP_COMMAND);
}
//***********************************************
// process profile file
@ -202,9 +55,6 @@ static void disable_file(OPERATION op, const char *filename) {
assert(op <OPERATION_MAX);
last_disable = UNSUCCESSFUL;
// rebuild /run/firejail directory in case tmpfs was mounted on top of /run
fs_build_firejail_dir();
// Resolve all symlinks
char* fname = realpath(filename, NULL);
if (fname == NULL && errno != EACCES) {
@ -868,9 +718,6 @@ void fs_overlayfs(void) {
if (major == 3 && minor < 18)
oldkernel = 1;
// build overlay directories
fs_build_mnt_dir();
char *oroot;
if(asprintf(&oroot, "%s/oroot", RUN_MNT_DIR) == -1)
errExit("asprintf");
@ -1194,17 +1041,33 @@ void fs_chroot(const char *rootdir) {
free(newx11);
}
// some older distros don't have a /run directory
// create one by default
// no exit on error, let the user deal with any problems
// create /run/firejail directory in chroot
char *rundir;
if (asprintf(&rundir, "%s/run", rootdir) == -1)
errExit("asprintf");
if (!is_dir(rundir)) {
int rv = mkdir(rundir, 0755);
(void) rv;
rv = chown(rundir, 0, 0);
(void) rv;
create_empty_dir_as_root(rundir, 0755);
free(rundir);
if (asprintf(&rundir, "%s/run/firejail", rootdir) == -1)
errExit("asprintf");
create_empty_dir_as_root(rundir, 0755);
free(rundir);
// create /run/firejail/mnt directory in chroot and mount a tmpfs
if (asprintf(&rundir, "%s/run/firejail/mnt", rootdir) == -1)
errExit("asprintf");
create_empty_dir_as_root(rundir, 0755);
if (mount("tmpfs", rundir, "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0)
errExit("mounting /run/firejail/mnt");
fs_logger2("tmpfs", RUN_MNT_DIR);
free(rundir);
// retrieve seccomp.protocol
struct stat s;
if (stat(RUN_SECCOMP_PROTOCOL, &s) == 0) {
if (asprintf(&rundir, "%s%s", rootdir, RUN_SECCOMP_PROTOCOL) == -1)
errExit("asprintf");
copy_file(RUN_SECCOMP_PROTOCOL, rundir, getuid(), getgid(), 0644);
free(rundir);
}
// copy /etc/resolv.conf in chroot directory
@ -1228,8 +1091,9 @@ void fs_chroot(const char *rootdir) {
printf("Chrooting into %s\n", rootdir);
if (chroot(rootdir) < 0)
errExit("chroot");
// mount a new tmpfs in /run/firejail/mnt - the old one was lost in chroot
fs_build_remount_mnt_dir();
// create all other /run/firejail files and directories
preproc_build_firejail_dir();
if (checkcfg(CFG_CHROOT_DESKTOP)) {
// update /var directory in order to support multiple sandboxes running on the same root directory
@ -1254,12 +1118,4 @@ void fs_chroot(const char *rootdir) {
}
#endif
void fs_private_tmp(void) {
// mount tmpfs on top of /run/firejail/mnt
if (arg_debug)
printf("Mounting tmpfs on /tmp directory\n");
if (mount("tmpfs", "/tmp", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=1777,gid=0") < 0)
errExit("mounting tmpfs on /tmp directory");
fs_logger2("tmpfs", "/tmp");
}

View file

@ -211,7 +211,6 @@ void fs_private_bin_list(void) {
assert(private_list);
// create /run/firejail/mnt/bin directory
fs_build_mnt_dir();
if (mkdir(RUN_BIN_DIR, 0755) == -1)
errExit("mkdir");
if (chmod(RUN_BIN_DIR, 0755) == -1)

View file

@ -129,8 +129,6 @@ void fs_private_dev(void){
printf("Mounting tmpfs on /dev\n");
// create DRI_DIR
fs_build_mnt_dir();
// keep a copy of dev directory
if (mkdir(RUN_DEV_DIR, 0755) == -1)
errExit("mkdir");

View file

@ -131,7 +131,6 @@ void fs_private_etc_list(void) {
}
// create /run/firejail/mnt/etc directory
fs_build_mnt_dir();
if (mkdir(RUN_ETC_DIR, 0755) == -1)
errExit("mkdir");
if (chmod(RUN_ETC_DIR, 0755) == -1)

View file

@ -104,8 +104,6 @@ static void skel(const char *homedir, uid_t u, gid_t g) {
static int store_xauthority(void) {
// put a copy of .Xauthority in XAUTHORITY_FILE
fs_build_mnt_dir();
char *src;
char *dest = RUN_XAUTHORITY_FILE;
if (asprintf(&src, "%s/.Xauthority", cfg.homedir) == -1)
@ -130,9 +128,6 @@ static int store_xauthority(void) {
}
static int store_asoundrc(void) {
// put a copy of .Xauthority in XAUTHORITY_FILE
fs_build_mnt_dir();
char *src;
char *dest = RUN_ASOUNDRC_FILE;
if (asprintf(&src, "%s/.asoundrc", cfg.homedir) == -1)
@ -592,7 +587,6 @@ void fs_private_home_list(void) {
}
// create /run/firejail/mnt/home directory
fs_build_mnt_dir();
int rv = mkdir(RUN_HOME_DIR, 0755);
if (rv == -1)
errExit("mkdir");

View file

@ -27,7 +27,6 @@
void fs_hostname(const char *hostname) {
struct stat s;
fs_build_mnt_dir();
// create a new /etc/hostname
if (stat("/etc/hostname", &s) == 0) {
@ -100,7 +99,6 @@ void fs_resolvconf(void) {
return;
struct stat s;
fs_build_mnt_dir();
// create a new /etc/hostname
if (stat("/etc/resolv.conf", &s) == 0) {

View file

@ -44,9 +44,6 @@ void fs_trace_preload(void) {
}
void fs_trace(void) {
// create /run/firejail/mnt directory
fs_build_mnt_dir();
// create the new ld.so.preload file and mount-bind it
if (arg_debug)
printf("Create the new ld.so.preload file\n");

View file

@ -317,9 +317,6 @@ void fs_var_utmp(void) {
return;
}
// create /run/firejail/mnt directory
fs_build_mnt_dir();
// create a new utmp file
if (arg_debug)
printf("Create the new utmp file\n");

View file

@ -529,10 +529,6 @@ void fs_whitelist(void) {
entry = entry->next;
}
// create mount points
fs_build_mnt_dir();
// /home/user
if (home_dir) {
// keep a copy of real home dir in RUN_WHITELIST_HOME_USER_DIR

View file

@ -404,7 +404,7 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
#ifdef HAVE_SECCOMP
else if (strcmp(argv[i], "--debug-syscalls") == 0) {
if (checkcfg(CFG_SECCOMP)) {
int rv = sbox_run(SBOX_USER | SBOX_CAPS | SBOX_SECCOMP, 2, PATH_FSECCOMP, "debug-syscalls");
int rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 2, PATH_FSECCOMP, "debug-syscalls");
exit(rv);
}
else {
@ -414,7 +414,7 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
}
else if (strcmp(argv[i], "--debug-errnos") == 0) {
if (checkcfg(CFG_SECCOMP)) {
int rv = sbox_run(SBOX_USER | SBOX_CAPS | SBOX_SECCOMP, 2, PATH_FSECCOMP, "debug-errnos");
int rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 2, PATH_FSECCOMP, "debug-errnos");
exit(rv);
}
else {
@ -439,7 +439,7 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
exit(0);
}
else if (strcmp(argv[i], "--debug-protocols") == 0) {
int rv = sbox_run(SBOX_USER | SBOX_CAPS | SBOX_SECCOMP, 2, PATH_FSECCOMP, "debug-protocols");
int rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 2, PATH_FSECCOMP, "debug-protocols");
exit(rv);
}
else if (strncmp(argv[i], "--protocol.print=", 17) == 0) {
@ -499,15 +499,15 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
exit(0);
}
else if (strcmp(argv[i], "--list") == 0) {
int rv = sbox_run(SBOX_USER | SBOX_CAPS | SBOX_SECCOMP, 2, PATH_FIREMON, "--list");
int rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 2, PATH_FIREMON, "--list");
exit(rv);
}
else if (strcmp(argv[i], "--tree") == 0) {
int rv = sbox_run(SBOX_USER | SBOX_CAPS | SBOX_SECCOMP, 2, PATH_FIREMON, "--tree");
int rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 2, PATH_FIREMON, "--tree");
exit(rv);
}
else if (strcmp(argv[i], "--top") == 0) {
int rv = sbox_run(SBOX_USER | SBOX_CAPS | SBOX_SECCOMP, 2, PATH_FIREMON, "--top");
int rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 2, PATH_FIREMON, "--top");
exit(rv);
}
#ifdef HAVE_NETWORK
@ -516,9 +516,9 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
struct stat s;
int rv;
if (stat("/proc/sys/kernel/grsecurity", &s) == 0)
rv = sbox_run(SBOX_ROOT | SBOX_CAPS | SBOX_SECCOMP, 2, PATH_FIREMON, "--netstats");
rv = sbox_run(SBOX_ROOT | SBOX_CAPS_NONE | SBOX_SECCOMP, 2, PATH_FIREMON, "--netstats");
else
rv = sbox_run(SBOX_USER | SBOX_CAPS | SBOX_SECCOMP, 2, PATH_FIREMON, "--netstats");
rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 2, PATH_FIREMON, "--netstats");
exit(rv);
}
else {
@ -855,6 +855,9 @@ int main(int argc, char **argv) {
int highest_errno = errno_highest_nr();
#endif
// build /run/firejail directory structure
preproc_build_firejail_dir();
detect_quiet(argc, argv);
detect_allow_debuggers(argc, argv);
@ -957,10 +960,8 @@ int main(int argc, char **argv) {
// initialize globals
init_cfg(argc, argv);
// check firejail directories
EUID_ROOT();
fs_build_firejail_dir();
bandwidth_del_run_file(sandbox_pid);
network_del_run_file(sandbox_pid);
delete_name_file(sandbox_pid);
@ -1462,35 +1463,6 @@ int main(int argc, char **argv) {
}
}
#if 0 // disabled for now, it could be used to overwrite system directories
else if (strncmp(argv[i], "--overlay-path=", 15) == 0) {
if (checkcfg(CFG_OVERLAYFS)) {
if (cfg.chrootdir) {
fprintf(stderr, "Error: --overlay and --chroot options are mutually exclusive\n");
exit(1);
}
struct stat s;
if (stat("/proc/sys/kernel/grsecurity", &s) == 0) {
fprintf(stderr, "Error: --overlay option is not available on Grsecurity systems\n");
exit(1);
}
arg_overlay = 1;
arg_overlay_keep = 1;
arg_overlay_reuse = 1;
char *dirname = argv[i] + 15;
if (dirname == '\0') {
fprintf(stderr, "Error: invalid overlay option\n");
exit(1);
}
cfg.overlay_dir = expand_home(dirname, cfg.homedir);
}
else {
fprintf(stderr, "Error: overlayfs feature is disabled in Firejail configuration file\n");
exit(1);
}
}
#endif
else if (strcmp(argv[i], "--overlay-tmpfs") == 0) {
if (checkcfg(CFG_OVERLAYFS)) {
if (cfg.chrootdir) {

View file

@ -28,70 +28,6 @@
#include <net/route.h>
#include <linux/if_bridge.h>
// scan interfaces in current namespace and print IP address/mask for each interface
void net_ifprint(void) {
uint32_t ip;
uint32_t mask;
struct ifaddrs *ifaddr, *ifa;
if (getifaddrs(&ifaddr) == -1)
errExit("getifaddrs");
printf("%-17.17s%-19.19s%-17.17s%-17.17s%-6.6s\n",
"Interface", "MAC", "IP", "Mask", "Status");
// walk through the linked list
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
if (ifa->ifa_addr == NULL)
continue;
if (ifa->ifa_addr->sa_family == AF_INET) {
struct sockaddr_in *si = (struct sockaddr_in *) ifa->ifa_netmask;
mask = ntohl(si->sin_addr.s_addr);
si = (struct sockaddr_in *) ifa->ifa_addr;
ip = ntohl(si->sin_addr.s_addr);
// interface status
char *status;
if (ifa->ifa_flags & IFF_RUNNING && ifa->ifa_flags & IFF_UP)
status = "UP";
else
status = "DOWN";
// ip address and mask
char ipstr[30];
sprintf(ipstr, "%d.%d.%d.%d", PRINT_IP(ip));
char maskstr[30];
sprintf(maskstr, "%d.%d.%d.%d", PRINT_IP(mask));
// mac address
unsigned char mac[6];
net_get_mac(ifa->ifa_name, mac);
char macstr[30];
if (strcmp(ifa->ifa_name, "lo") == 0)
macstr[0] = '\0';
else
sprintf(macstr, "%02x:%02x:%02x:%02x:%02x:%02x", PRINT_MAC(mac));
// print
printf("%-17.17s%-19.19s%-17.17s%-17.17s%-6.6s\n",
ifa->ifa_name, macstr, ipstr, maskstr, status);
// network scanning
if (!arg_scan) // scanning disabled
continue;
if (strcmp(ifa->ifa_name, "lo") == 0) // no loopbabck scanning
continue;
if (mask2bits(mask) < 16) // not scanning large networks
continue;
if (!ip) // if not configured
continue;
// only if the interface is up and running
if (ifa->ifa_flags & IFF_RUNNING && ifa->ifa_flags & IFF_UP)
arp_scan(ifa->ifa_name, ip, mask);
}
}
freeifaddrs(ifaddr);
}
int net_get_mtu(const char *ifname) {
int mtu = 0;
@ -190,101 +126,11 @@ void net_if_up(const char *ifname) {
fprintf(stderr, "Error: invalid network device name %s\n", ifname);
exit(1);
}
int sock = socket(AF_INET,SOCK_DGRAM,0);
if (sock < 0)
errExit("socket");
sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 3,
PATH_FNET, "ifup", ifname);
}
// get the existing interface flags
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
ifr.ifr_addr.sa_family = AF_INET;
// read the existing flags
if (ioctl(sock, SIOCGIFFLAGS, &ifr ) < 0) {
close(sock);
printf("Error: cannot bring up interface %s\n", ifname);
errExit("ioctl");
}
ifr.ifr_flags |= IFF_UP;
// set the new flags
if (ioctl( sock, SIOCSIFFLAGS, &ifr ) < 0) {
close(sock);
printf("Error: cannot bring up interface %s\n", ifname);
errExit("ioctl");
}
// checking
// read the existing flags
if (ioctl(sock, SIOCGIFFLAGS, &ifr ) < 0) {
close(sock);
printf("Error: cannot bring up interface %s\n", ifname);
errExit("ioctl");
}
// wait not more than 500ms for the interface to come up
int cnt = 0;
while (cnt < 50) {
usleep(10000); // sleep 10ms
// read the existing flags
if (ioctl(sock, SIOCGIFFLAGS, &ifr ) < 0) {
close(sock);
printf("Error: cannot bring up interface %s\n", ifname);
errExit("ioctl");
}
if (ifr.ifr_flags & IFF_RUNNING)
break;
cnt++;
}
close(sock);
}
// bring interface up
void net_if_down(const char *ifname) {
if (strlen(ifname) > IFNAMSIZ) {
fprintf(stderr, "Error: invalid network device name %s\n", ifname);
exit(1);
}
int sock = socket(AF_INET,SOCK_DGRAM,0);
if (sock < 0)
errExit("socket");
// get the existing interface flags
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
ifr.ifr_addr.sa_family = AF_INET;
// read the existing flags
if (ioctl(sock, SIOCGIFFLAGS, &ifr ) < 0) {
close(sock);
printf("Error: cannot shut down interface %s\n", ifname);
errExit("ioctl");
}
ifr.ifr_flags &= ~IFF_UP;
// set the new flags
if (ioctl( sock, SIOCSIFFLAGS, &ifr ) < 0) {
close(sock);
printf("Error: cannot shut down interface %s\n", ifname);
errExit("ioctl");
}
close(sock);
}
struct ifreq6 {
struct in6_addr ifr6_addr;
uint32_t ifr6_prefixlen;
unsigned int ifr6_ifindex;
};
// configure interface ipv6 address
// ex: firejail --net=eth0 --ip6=2001:0db8:0:f101::1/64
void net_if_ip6(const char *ifname, const char *addr6) {
@ -293,107 +139,11 @@ void net_if_ip6(const char *ifname, const char *addr6) {
exit(1);
}
// extract prefix
unsigned long prefix;
char *ptr;
if ((ptr = strchr(addr6, '/'))) {
prefix = atol(ptr + 1);
if (prefix > 128) {
fprintf(stderr, "Error: invalid prefix for IPv6 address %s\n", addr6);
exit(1);
}
*ptr = '\0'; // mark the end of the address
}
else
prefix = 128;
sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 5,
PATH_FNET, "config", "ipv6", ifname, addr6);
// extract address
struct sockaddr_in6 sin6;
memset(&sin6, 0, sizeof(sin6));
sin6.sin6_family = AF_INET6;
int rv = inet_pton(AF_INET6, addr6, sin6.sin6_addr.s6_addr);
if (rv <= 0) {
fprintf(stderr, "Error: invalid IPv6 address %s\n", addr6);
exit(1);
}
// open socket
int sock = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
if (sock < 0) {
fprintf(stderr, "Error: IPv6 is not supported on this system\n");
exit(1);
}
// find interface index
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
ifr.ifr_addr.sa_family = AF_INET;
if (ioctl(sock, SIOGIFINDEX, &ifr) < 0) {
perror("ioctl SIOGIFINDEX");
exit(1);
}
// configure address
struct ifreq6 ifr6;
memset(&ifr6, 0, sizeof(ifr6));
ifr6.ifr6_prefixlen = prefix;
ifr6.ifr6_ifindex = ifr.ifr_ifindex;
memcpy((char *) &ifr6.ifr6_addr, (char *) &sin6.sin6_addr, sizeof(struct in6_addr));
if (ioctl(sock, SIOCSIFADDR, &ifr6) < 0) {
perror("ioctl SIOCSIFADDR");
exit(1);
}
close(sock);
}
// configure interface ipv4 address
void net_if_ip(const char *ifname, uint32_t ip, uint32_t mask, int mtu) {
if (strlen(ifname) > IFNAMSIZ) {
fprintf(stderr, "Error: invalid network device name %s\n", ifname);
exit(1);
}
if (arg_debug)
printf("configure interface %s\n", ifname);
int sock = socket(AF_INET,SOCK_DGRAM,0);
if (sock < 0)
errExit("socket");
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
ifr.ifr_addr.sa_family = AF_INET;
((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr = htonl(ip);
if (ioctl( sock, SIOCSIFADDR, &ifr ) < 0) {
close(sock);
errExit("ioctl");
}
if (ip != 0) {
((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr = htonl(mask);
if (ioctl( sock, SIOCSIFNETMASK, &ifr ) < 0) {
close(sock);
errExit("ioctl");
}
}
// configure mtu
if (mtu > 0) {
ifr.ifr_mtu = mtu;
if (ioctl( sock, SIOCSIFMTU, &ifr ) < 0) {
close(sock);
errExit("ioctl");
}
}
close(sock);
usleep(10000); // sleep 10ms
}
// add an IP route, return -1 if error, 0 if the route was added
int net_add_route(uint32_t ip, uint32_t mask, uint32_t gw) {
int sock;
@ -464,20 +214,15 @@ uint32_t network_get_defaultgw(void) {
}
int net_config_mac(const char *ifname, const unsigned char mac[6]) {
struct ifreq ifr;
int sock;
char *macstr;
if (asprintf(&macstr, "%02x:%02x:%02x:%02x:%02x:%02x",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]) == -1)
errExit("asprintf");
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
errExit("socket");
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
memcpy(ifr.ifr_hwaddr.sa_data, mac, 6);
sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 5,
PATH_FNET, "config", "mac", ifname, macstr);
if (ioctl(sock, SIOCSIFHWADDR, &ifr) == -1)
errExit("ioctl");
close(sock);
free(macstr);
return 0;
}
@ -500,3 +245,27 @@ int net_get_mac(const char *ifname, unsigned char mac[6]) {
close(sock);
return 0;
}
void net_config_interface(const char *dev, uint32_t ip, uint32_t mask, int mtu) {
assert(dev);
char *ipstr;
if (asprintf(&ipstr, "%llu", (long long unsigned) ip) == -1)
errExit("asprintf");
char *maskstr;
if (asprintf(&maskstr, "%llu", (long long unsigned) mask) == -1)
errExit("asprintf");
char *mtustr;
if (asprintf(&mtustr, "%d", mtu) == -1)
errExit("asprintf");
sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 7,
PATH_FNET, "config", "interface", dev, ipstr, maskstr, mtustr);
free(ipstr);
free(maskstr);
free(mtustr);
}

View file

@ -128,11 +128,10 @@ void net_configure_veth_pair(Bridge *br, const char *ifname, pid_t child) {
else
dev = br->veth_name;
// net_create_veth(dev, ifname, child);
char *cstr;
if (asprintf(&cstr, "%d", child) == -1)
errExit("asprintf");
sbox_run(SBOX_ROOT | SBOX_SECCOMP, 7, PATH_FNET, "create", "veth", dev, ifname, br->dev, cstr);
sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 7, PATH_FNET, "create", "veth", dev, ifname, br->dev, cstr);
free(cstr);
char *msg;
@ -300,50 +299,42 @@ void network_main(pid_t child) {
net_configure_veth_pair(&cfg.bridge0, "eth0", child);
}
else
// net_create_macvlan(cfg.bridge0.devsandbox, cfg.bridge0.dev, child);
sbox_run(SBOX_ROOT | SBOX_SECCOMP, 6, PATH_FNET, "create", "macvlan", cfg.bridge0.devsandbox, cfg.bridge0.dev, cstr);
sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 6, PATH_FNET, "create", "macvlan", cfg.bridge0.devsandbox, cfg.bridge0.dev, cstr);
}
if (cfg.bridge1.configured) {
if (cfg.bridge1.macvlan == 0)
net_configure_veth_pair(&cfg.bridge1, "eth1", child);
else
// net_create_macvlan(cfg.bridge1.devsandbox, cfg.bridge1.dev, child);
sbox_run(SBOX_ROOT | SBOX_SECCOMP, 6, PATH_FNET, "create", "macvlan", cfg.bridge1.devsandbox, cfg.bridge1.dev, cstr);
sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 6, PATH_FNET, "create", "macvlan", cfg.bridge1.devsandbox, cfg.bridge1.dev, cstr);
}
if (cfg.bridge2.configured) {
if (cfg.bridge2.macvlan == 0)
net_configure_veth_pair(&cfg.bridge2, "eth2", child);
else
// net_create_macvlan(cfg.bridge2.devsandbox, cfg.bridge2.dev, child);
sbox_run(SBOX_ROOT | SBOX_SECCOMP, 6, PATH_FNET, "create", "macvlan", cfg.bridge2.devsandbox, cfg.bridge2.dev, cstr);
sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 6, PATH_FNET, "create", "macvlan", cfg.bridge2.devsandbox, cfg.bridge2.dev, cstr);
}
if (cfg.bridge3.configured) {
if (cfg.bridge3.macvlan == 0)
net_configure_veth_pair(&cfg.bridge3, "eth3", child);
else
// net_create_macvlan(cfg.bridge3.devsandbox, cfg.bridge3.dev, child);
sbox_run(SBOX_ROOT | SBOX_SECCOMP, 6, PATH_FNET, "create", "macvlan", cfg.bridge3.devsandbox, cfg.bridge3.dev, cstr);
sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 6, PATH_FNET, "create", "macvlan", cfg.bridge3.devsandbox, cfg.bridge3.dev, cstr);
}
// move interfaces in sandbox
if (cfg.interface0.configured) {
// net_move_interface(cfg.interface0.dev, child);
sbox_run(SBOX_ROOT | SBOX_SECCOMP, 4, PATH_FNET, "moveif", cfg.interface0.dev, cstr);
sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 4, PATH_FNET, "moveif", cfg.interface0.dev, cstr);
}
if (cfg.interface1.configured) {
// net_move_interface(cfg.interface1.dev, child);
sbox_run(SBOX_ROOT | SBOX_SECCOMP, 4, PATH_FNET, "moveif", cfg.interface1.dev, cstr);
sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 4, PATH_FNET, "moveif", cfg.interface1.dev, cstr);
}
if (cfg.interface2.configured) {
// net_move_interface(cfg.interface2.dev, child);
sbox_run(SBOX_ROOT | SBOX_SECCOMP, 4, PATH_FNET, "moveif", cfg.interface3.dev, cstr);
sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 4, PATH_FNET, "moveif", cfg.interface3.dev, cstr);
}
if (cfg.interface3.configured) {
// net_move_interface(cfg.interface3.dev, child);
sbox_run(SBOX_ROOT | SBOX_SECCOMP, 4, PATH_FNET, "moveif", cfg.interface3.dev, cstr);
sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 4, PATH_FNET, "moveif", cfg.interface3.dev, cstr);
}
free(cstr);

110
src/firejail/preproc.c Normal file
View file

@ -0,0 +1,110 @@
/*
* Copyright (C) 2014-2016 Firejail Authors
*
* This file is part of firejail project
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "firejail.h"
#include <sys/mount.h>
#include <sys/stat.h>
static int tmpfs_mounted = 0;
// build /run/firejail directory
void preproc_build_firejail_dir(void) {
struct stat s;
// CentOS 6 doesn't have /run directory
if (stat(RUN_FIREJAIL_BASEDIR, &s)) {
create_empty_dir_as_root(RUN_FIREJAIL_BASEDIR, 0755);
}
if (stat(RUN_FIREJAIL_DIR, &s)) {
create_empty_dir_as_root(RUN_FIREJAIL_DIR, 0755);
}
if (stat(RUN_FIREJAIL_NETWORK_DIR, &s)) {
create_empty_dir_as_root(RUN_FIREJAIL_NETWORK_DIR, 0755);
}
if (stat(RUN_FIREJAIL_BANDWIDTH_DIR, &s)) {
create_empty_dir_as_root(RUN_FIREJAIL_BANDWIDTH_DIR, 0755);
}
if (stat(RUN_FIREJAIL_NAME_DIR, &s)) {
create_empty_dir_as_root(RUN_FIREJAIL_NAME_DIR, 0755);
}
if (stat(RUN_FIREJAIL_X11_DIR, &s)) {
create_empty_dir_as_root(RUN_FIREJAIL_X11_DIR, 0755);
}
if (stat(RUN_FIREJAIL_APPIMAGE_DIR, &s)) {
create_empty_dir_as_root(RUN_FIREJAIL_APPIMAGE_DIR, 0755);
}
create_empty_file_as_root(RUN_RO_FILE, S_IRUSR);
create_empty_dir_as_root(RUN_RO_DIR, S_IRUSR);
}
// build /run/firejail/mnt directory
void preproc_mount_mnt_dir(void) {
struct stat s;
// mount tmpfs on top of /run/firejail/mnt
if (!tmpfs_mounted) {
if (arg_debug)
printf("Mounting tmpfs on %s directory\n", RUN_MNT_DIR);
if (mount("tmpfs", RUN_MNT_DIR, "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0)
errExit("mounting /run/firejail/mnt");
tmpfs_mounted = 1;
fs_logger2("tmpfs", RUN_MNT_DIR);
}
}
// grab a copy of cp command
void preproc_build_cp_command(void) {
struct stat s;
preproc_mount_mnt_dir();
if (stat(RUN_CP_COMMAND, &s)) {
char* fname = realpath("/bin/cp", NULL);
if (fname == NULL) {
fprintf(stderr, "Error: /bin/cp not found\n");
exit(1);
}
if (stat(fname, &s)) {
fprintf(stderr, "Error: /bin/cp not found\n");
exit(1);
}
if (is_link(fname)) {
fprintf(stderr, "Error: invalid /bin/cp file\n");
exit(1);
}
int rv = copy_file(fname, RUN_CP_COMMAND, 0, 0, 0755);
if (rv) {
fprintf(stderr, "Error: cannot access /bin/cp\n");
exit(1);
}
ASSERT_PERMS(RUN_CP_COMMAND, 0, 0, 0755);
free(fname);
}
}
// delete the temporary cp command
void preproc_delete_cp_command(void) {
unlink(RUN_CP_COMMAND);
}

View file

@ -70,8 +70,6 @@ void protocol_filter(const char *fname) {
void protocol_filter_save(void) {
// save protocol filter configuration in PROTOCOL_CFG
fs_build_mnt_dir();
FILE *fp = fopen(RUN_PROTOCOL_CFG, "w");
if (!fp)
errExit("fopen");

View file

@ -104,7 +104,6 @@ void pulseaudio_init(void) {
return;
// create the new user pulseaudio directory
fs_build_mnt_dir();
int rv = mkdir(RUN_PULSE_DIR, 0700);
(void) rv; // in --chroot mode the directory can already be there
if (chown(RUN_PULSE_DIR, getuid(), getgid()) < 0)

View file

@ -73,7 +73,6 @@ static void sanitize_home(void) {
return;
}
fs_build_mnt_dir();
if (mkdir(RUN_WHITELIST_HOME_DIR, 0755) == -1)
errExit("mkdir");
@ -127,7 +126,6 @@ static void sanitize_passwd(void) {
FILE *fpin = NULL;
FILE *fpout = NULL;
fs_build_mnt_dir();
// open files
/* coverity[toctou] */
@ -261,7 +259,6 @@ static void sanitize_group(void) {
FILE *fpin = NULL;
FILE *fpout = NULL;
fs_build_mnt_dir();
// open files
/* coverity[toctou] */

View file

@ -122,7 +122,7 @@ static void sandbox_if_up(Bridge *br) {
assert(br);
if (!br->configured)
return;
char *dev = br->devsandbox;
net_if_up(dev);
@ -137,8 +137,7 @@ static void sandbox_if_up(Bridge *br) {
assert(br->ipsandbox);
if (arg_debug)
printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(br->ipsandbox), dev);
net_if_ip(dev, br->ipsandbox, br->mask, br->mtu);
net_if_up(dev);
net_config_interface(dev, br->ipsandbox, br->mask, br->mtu);
}
else if (br->arg_ip_none == 0 && br->macvlan == 1) {
// reassign the macvlan address
@ -160,8 +159,7 @@ static void sandbox_if_up(Bridge *br) {
if (arg_debug)
printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(br->ipsandbox), dev);
net_if_ip(dev, br->ipsandbox, br->mask, br->mtu);
net_if_up(dev);
net_config_interface(dev, br->ipsandbox, br->mask, br->mtu);
}
if (br->ip6sandbox)
@ -256,32 +254,6 @@ static int monitor_application(pid_t app_pid) {
// return the latest exit status.
return status;
#if 0
// todo: find a way to shut down interfaces before closing the namespace
// the problem is we don't have enough privileges to shutdown interfaces in this moment
// shut down bridge/macvlan interfaces
if (any_bridge_configured()) {
if (cfg.bridge0.configured) {
printf("Shutting down %s\n", cfg.bridge0.devsandbox);
net_if_down( cfg.bridge0.devsandbox);
}
if (cfg.bridge1.configured) {
printf("Shutting down %s\n", cfg.bridge1.devsandbox);
net_if_down( cfg.bridge1.devsandbox);
}
if (cfg.bridge2.configured) {
printf("Shutting down %s\n", cfg.bridge2.devsandbox);
net_if_down( cfg.bridge2.devsandbox);
}
if (cfg.bridge3.configured) {
printf("Shutting down %s\n", cfg.bridge3.devsandbox);
net_if_down( cfg.bridge3.devsandbox);
}
usleep(20000); // 20 ms sleep
}
#endif
}
void start_audit(void) {
@ -442,7 +414,8 @@ int sandbox(void* sandbox_arg) {
if (mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL) < 0) {
chk_chroot();
}
// ... and mount a tmpfs on top of /run/firejail/mnt directory
preproc_mount_mnt_dir();
//****************************
// log sandbox data
@ -459,7 +432,7 @@ int sandbox(void* sandbox_arg) {
fs_logger("install mount namespace");
//****************************
// netfilter etc.
// netfilter
//****************************
if (arg_netfilter && any_bridge_configured()) { // assuming by default the client filter
netfilter(arg_netfilter_file);
@ -468,6 +441,105 @@ int sandbox(void* sandbox_arg) {
netfilter6(arg_netfilter6_file);
}
//****************************
// networking
//****************************
int gw_cfg_failed = 0; // default gw configuration flag
if (arg_nonetwork) {
net_if_up("lo");
if (arg_debug)
printf("Network namespace enabled, only loopback interface available\n");
}
else if (any_bridge_configured() || any_interface_configured()) {
// configure lo and eth0...eth3
net_if_up("lo");
if (mac_not_zero(cfg.bridge0.macsandbox))
net_config_mac(cfg.bridge0.devsandbox, cfg.bridge0.macsandbox);
sandbox_if_up(&cfg.bridge0);
if (mac_not_zero(cfg.bridge1.macsandbox))
net_config_mac(cfg.bridge1.devsandbox, cfg.bridge1.macsandbox);
sandbox_if_up(&cfg.bridge1);
if (mac_not_zero(cfg.bridge2.macsandbox))
net_config_mac(cfg.bridge2.devsandbox, cfg.bridge2.macsandbox);
sandbox_if_up(&cfg.bridge2);
if (mac_not_zero(cfg.bridge3.macsandbox))
net_config_mac(cfg.bridge3.devsandbox, cfg.bridge3.macsandbox);
sandbox_if_up(&cfg.bridge3);
// todo: this code seems to be dead!!!
// enable interfaces
if (cfg.interface0.configured && cfg.interface0.ip) {
assert(0);
if (arg_debug)
printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(cfg.interface0.ip), cfg.interface0.dev);
net_config_interface(cfg.interface0.dev, cfg.interface0.ip, cfg.interface0.mask, cfg.interface0.mtu);
}
if (cfg.interface1.configured && cfg.interface1.ip) {
assert(0);
if (arg_debug)
printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(cfg.interface1.ip), cfg.interface1.dev);
net_config_interface(cfg.interface1.dev, cfg.interface1.ip, cfg.interface1.mask, cfg.interface1.mtu);
}
if (cfg.interface2.configured && cfg.interface2.ip) {
assert(0);
if (arg_debug)
printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(cfg.interface2.ip), cfg.interface2.dev);
net_config_interface(cfg.interface2.dev, cfg.interface2.ip, cfg.interface2.mask, cfg.interface2.mtu);
}
if (cfg.interface3.configured && cfg.interface3.ip) {
assert(0);
if (arg_debug)
printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(cfg.interface3.ip), cfg.interface3.dev);
net_config_interface(cfg.interface3.dev, cfg.interface3.ip, cfg.interface3.mask, cfg.interface3.mtu);
}
// add a default route
if (cfg.defaultgw) {
// set the default route
if (net_add_route(0, 0, cfg.defaultgw)) {
fprintf(stderr, "Warning: cannot configure default route\n");
gw_cfg_failed = 1;
}
}
if (arg_debug)
printf("Network namespace enabled\n");
}
// print network configuration
if (!arg_quiet) {
if (any_bridge_configured() || any_interface_configured() || cfg.defaultgw || cfg.dns1) {
printf("\n");
if (any_bridge_configured() || any_interface_configured()) {
// net_ifprint();
if (arg_scan)
sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 3, PATH_FNET, "printif", "scan");
else
sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 2, PATH_FNET, "printif", "scan");
}
if (cfg.defaultgw != 0) {
if (gw_cfg_failed)
printf("Default gateway configuration failed\n");
else
printf("Default gateway %d.%d.%d.%d\n", PRINT_IP(cfg.defaultgw));
}
if (cfg.dns1 != 0)
printf("DNS server %d.%d.%d.%d\n", PRINT_IP(cfg.dns1));
if (cfg.dns2 != 0)
printf("DNS server %d.%d.%d.%d\n", PRINT_IP(cfg.dns2));
if (cfg.dns3 != 0)
printf("DNS server %d.%d.%d.%d\n", PRINT_IP(cfg.dns3));
printf("\n");
}
}
// load IBUS env variables
if (arg_nonetwork || any_bridge_configured() || any_interface_configured()) {
// do nothing - there are problems with ibus version 1.5.11
@ -475,9 +547,34 @@ int sandbox(void* sandbox_arg) {
else
env_ibus_load();
// grab a copy of cp command
fs_build_cp_command();
//****************************
// fs pre-processing:
// - copy some commands under /run
// - build seccomp filters
// - create an empty /etc/ld.so.preload
//****************************
preproc_build_cp_command();
#ifdef HAVE_SECCOMP
if (cfg.protocol) {
if (arg_debug)
printf("Build protocol filter: %s\n", cfg.protocol);
// as root, create RUN_SECCOMP_PROTOCOL file
// this is where fseccomp program will store the protocol filter
create_empty_file_as_root(RUN_SECCOMP_PROTOCOL, 0644);
if (chown(RUN_SECCOMP_PROTOCOL, getuid(), getgid()) == -1)
errExit("chown");
if (chmod(RUN_SECCOMP_PROTOCOL, 0644) == -1)
errExit("chmod");
// build the seccomp filter as a regular user
int rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 5,
PATH_FSECCOMP, "protocol", "build", cfg.protocol, RUN_SECCOMP_PROTOCOL);
if (rv)
exit(rv);
}
#endif
// trace pre-install
if (arg_trace || arg_tracelog || mask_x11_abstract_socket)
fs_trace_preload();
@ -494,7 +591,7 @@ int sandbox(void* sandbox_arg) {
enforce_seccomp = 1;
#endif
}
#ifdef HAVE_CHROOT
if (cfg.chrootdir) {
fs_chroot(cfg.chrootdir);
@ -617,7 +714,6 @@ int sandbox(void* sandbox_arg) {
EUID_USER();
profile_add("whitelist /tmp/.X11-unix");
EUID_ROOT();
// fs_private_tmp();
}
}
@ -664,102 +760,17 @@ int sandbox(void* sandbox_arg) {
fs_dev_disable_3d();
//****************************
// networking
// set dns
//****************************
int gw_cfg_failed = 0; // default gw configuration flag
if (arg_nonetwork) {
net_if_up("lo");
if (arg_debug)
printf("Network namespace enabled, only loopback interface available\n");
}
else if (any_bridge_configured() || any_interface_configured()) {
// configure lo and eth0...eth3
net_if_up("lo");
if (mac_not_zero(cfg.bridge0.macsandbox))
net_config_mac(cfg.bridge0.devsandbox, cfg.bridge0.macsandbox);
sandbox_if_up(&cfg.bridge0);
if (mac_not_zero(cfg.bridge1.macsandbox))
net_config_mac(cfg.bridge1.devsandbox, cfg.bridge1.macsandbox);
sandbox_if_up(&cfg.bridge1);
if (mac_not_zero(cfg.bridge2.macsandbox))
net_config_mac(cfg.bridge2.devsandbox, cfg.bridge2.macsandbox);
sandbox_if_up(&cfg.bridge2);
if (mac_not_zero(cfg.bridge3.macsandbox))
net_config_mac(cfg.bridge3.devsandbox, cfg.bridge3.macsandbox);
sandbox_if_up(&cfg.bridge3);
// enable interfaces
if (cfg.interface0.configured && cfg.interface0.ip) {
if (arg_debug)
printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(cfg.interface0.ip), cfg.interface0.dev);
net_if_ip(cfg.interface0.dev, cfg.interface0.ip, cfg.interface0.mask, cfg.interface0.mtu);
net_if_up(cfg.interface0.dev);
}
if (cfg.interface1.configured && cfg.interface1.ip) {
if (arg_debug)
printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(cfg.interface1.ip), cfg.interface1.dev);
net_if_ip(cfg.interface1.dev, cfg.interface1.ip, cfg.interface1.mask, cfg.interface1.mtu);
net_if_up(cfg.interface1.dev);
}
if (cfg.interface2.configured && cfg.interface2.ip) {
if (arg_debug)
printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(cfg.interface2.ip), cfg.interface2.dev);
net_if_ip(cfg.interface2.dev, cfg.interface2.ip, cfg.interface2.mask, cfg.interface2.mtu);
net_if_up(cfg.interface2.dev);
}
if (cfg.interface3.configured && cfg.interface3.ip) {
if (arg_debug)
printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(cfg.interface3.ip), cfg.interface3.dev);
net_if_ip(cfg.interface3.dev, cfg.interface3.ip, cfg.interface3.mask, cfg.interface3.mtu);
net_if_up(cfg.interface3.dev);
}
// add a default route
if (cfg.defaultgw) {
// set the default route
if (net_add_route(0, 0, cfg.defaultgw)) {
fprintf(stderr, "Warning: cannot configure default route\n");
gw_cfg_failed = 1;
}
}
if (arg_debug)
printf("Network namespace enabled\n");
}
// if any dns server is configured, it is time to set it now
fs_resolvconf();
//****************************
// fs post-processing
//****************************
preproc_delete_cp_command();
fs_logger_print();
fs_logger_change_owner();
// print network configuration
if (!arg_quiet) {
if (any_bridge_configured() || any_interface_configured() || cfg.defaultgw || cfg.dns1) {
printf("\n");
if (any_bridge_configured() || any_interface_configured())
net_ifprint();
if (cfg.defaultgw != 0) {
if (gw_cfg_failed)
printf("Default gateway configuration failed\n");
else
printf("Default gateway %d.%d.%d.%d\n", PRINT_IP(cfg.defaultgw));
}
if (cfg.dns1 != 0)
printf("DNS server %d.%d.%d.%d\n", PRINT_IP(cfg.dns1));
if (cfg.dns2 != 0)
printf("DNS server %d.%d.%d.%d\n", PRINT_IP(cfg.dns2));
if (cfg.dns3 != 0)
printf("DNS server %d.%d.%d.%d\n", PRINT_IP(cfg.dns3));
printf("\n");
}
}
fs_delete_cp_command();
//****************************
// set application environment
//****************************
@ -820,21 +831,7 @@ int sandbox(void* sandbox_arg) {
// install protocol filter
if (cfg.protocol) {
if (arg_debug)
printf("Set protocol filter: %s\n", cfg.protocol);
// as root, create RUN_SECCOMP_PROTOCOL file
// this is where fseccomp program will store the protocol filter
int dst = open(RUN_SECCOMP_PROTOCOL, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
if (dst == -1)
errExit("open");
close(dst);
if (chown(RUN_SECCOMP_PROTOCOL, getuid(), getgid()) == -1)
errExit("chown");
// build the seccomp filter as a regular user
int rv = sbox_run(SBOX_USER | SBOX_CAPS | SBOX_SECCOMP, 5,
PATH_FSECCOMP, "protocol", "build", cfg.protocol, RUN_SECCOMP_PROTOCOL);
if (rv)
exit(rv);
printf("Install protocol filter: %s\n", cfg.protocol);
protocol_filter(RUN_SECCOMP_PROTOCOL); // install filter
protocol_filter_save(); // save filter in RUN_PROTOCOL_CFG
}

View file

@ -125,21 +125,26 @@ int sbox_run(unsigned filter, int num, ...) {
arg[i] = NULL;
va_end(valist);
//#if 0
{
int i;
for (i = 0; i <= num; i++)
printf("#%s# ", arg[i]);
printf("\n");
}
//#endif
if (arg_debug) {
printf("sbox run: ");
for (i = 0; i <= num; i++)
printf("%s ", arg[i]);
printf("\n");
}
pid_t child = fork();
if (child < 0)
errExit("fork");
if (child == 0) {
// apply filters
if (filter & SBOX_CAPS)
if (filter & SBOX_CAPS_NONE) {
caps_drop_all();
}
else if (filter & SBOX_CAPS_NETWORK) {
uint64_t set = ((uint64_t) 1) << CAP_NET_ADMIN;
set |= ((uint64_t) 1) << CAP_NET_RAW;
caps_set(set);
}
if (filter & SBOX_SECCOMP) {
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {

View file

@ -275,7 +275,6 @@ static void filter_end_whitelist(void) {
// save seccomp filter in /run/firejail/mnt/seccomp
static void write_seccomp_file(void) {
fs_build_mnt_dir();
assert(sfilter);
int fd = open(RUN_SECCOMP_CFG, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR);

View file

@ -696,3 +696,37 @@ void flush_stdin(void) {
}
}
void create_empty_dir_as_root(const char *dir, mode_t mode) {
assert(dir);
struct stat s;
if (stat(dir, &s)) {
if (arg_debug)
printf("Creating empty %s directory\n", dir);
if (mkdir(dir, mode) == -1)
errExit("mkdir");
if (chmod(dir, mode) == -1)
errExit("chmod");
ASSERT_PERMS(dir, 0, 0, mode);
}
}
void create_empty_file_as_root(const char *fname, mode_t mode) {
assert(fname);
struct stat s;
if (stat(fname, &s)) {
if (arg_debug)
printf("Creating empty %s file\n", fname);
/* coverity[toctou] */
FILE *fp = fopen(fname, "w");
if (!fp)
errExit("fopen");
SET_PERMS_STREAM(fp, 0, 0, S_IRUSR);
fclose(fp);
}
}

208
src/fnet/arp.c Normal file
View file

@ -0,0 +1,208 @@
/*
* Copyright (C) 2014-2016 Firejail Authors
*
* This file is part of firejail project
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "fnet.h"
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <linux/if_ether.h> //TCP/IP Protocol Suite for Linux
#include <net/if.h>
#include <netinet/in.h>
#include <linux/ip.h>
#include <linux/udp.h>
#include <linux/tcp.h>
#include <linux/if_packet.h>
typedef struct arp_hdr_t {
uint16_t htype;
uint16_t ptype;
uint8_t hlen;
uint8_t plen;
uint16_t opcode;
uint8_t sender_mac[6];
uint8_t sender_ip[4];
uint8_t target_mac[6];
uint8_t target_ip[4];
} ArpHdr;
// scan interface (--scan option)
void arp_scan(const char *dev, uint32_t ifip, uint32_t ifmask) {
assert(dev);
assert(ifip);
// printf("Scanning interface %s (%d.%d.%d.%d/%d)\n",
// dev, PRINT_IP(ifip & ifmask), mask2bits(ifmask));
if (strlen(dev) > IFNAMSIZ) {
fprintf(stderr, "Error: invalid network device name %s\n", dev);
exit(1);
}
// find interface mac address
int sock;
if ((sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
errExit("socket");
struct ifreq ifr;
memset(&ifr, 0, sizeof (ifr));
strncpy(ifr.ifr_name, dev, IFNAMSIZ);
if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0)
errExit("ioctl");
close(sock);
uint8_t mac[6];
memcpy (mac, ifr.ifr_hwaddr.sa_data, 6);
// open layer2 socket
if ((sock = socket(PF_PACKET, SOCK_RAW, htons (ETH_P_ALL))) < 0)
errExit("socket");
// try all possible ip addresses in ascending order
uint32_t range = ~ifmask + 1; // the number of potential addresses
// this software is not supported for /31 networks
if (range < 4) {
fprintf(stderr, "Warning: this option is not supported for /31 networks\n");
close(sock);
return;
}
uint32_t dest = (ifip & ifmask) + 1;
uint32_t last = dest + range - 1;
uint32_t src = htonl(ifip);
// wait not more than one second for an answer
int header_printed = 0;
uint32_t last_ip = 0;
struct timeval ts;
ts.tv_sec = 2; // 2 seconds receive timeout
ts.tv_usec = 0;
while (1) {
fd_set rfds;
FD_ZERO(&rfds);
FD_SET(sock, &rfds);
fd_set wfds;
FD_ZERO(&wfds);
FD_SET(sock, &wfds);
int maxfd = sock;
uint8_t frame[ETH_FRAME_LEN]; // includes eht header, vlan, and crc
memset(frame, 0, ETH_FRAME_LEN);
int nready;
if (dest < last)
nready = select(maxfd + 1, &rfds, &wfds, (fd_set *) 0, NULL);
else
nready = select(maxfd + 1, &rfds, (fd_set *) 0, (fd_set *) 0, &ts);
if (nready < 0)
errExit("select");
if (nready == 0) { // timeout
break;
}
if (FD_ISSET(sock, &wfds) && dest < last) {
// configure layer2 socket address information
struct sockaddr_ll addr;
memset(&addr, 0, sizeof(addr));
if ((addr.sll_ifindex = if_nametoindex(dev)) == 0)
errExit("if_nametoindex");
addr.sll_family = AF_PACKET;
memcpy (addr.sll_addr, mac, 6);
addr.sll_halen = htons(6);
// build the arp packet header
ArpHdr hdr;
memset(&hdr, 0, sizeof(hdr));
hdr.htype = htons(1);
hdr.ptype = htons(ETH_P_IP);
hdr.hlen = 6;
hdr.plen = 4;
hdr.opcode = htons(1); //ARPOP_REQUEST
memcpy(hdr.sender_mac, mac, 6);
memcpy(hdr.sender_ip, (uint8_t *)&src, 4);
uint32_t dst = htonl(dest);
memcpy(hdr.target_ip, (uint8_t *)&dst, 4);
// build ethernet frame
uint8_t frame[ETH_FRAME_LEN]; // includes eht header, vlan, and crc
memset(frame, 0, sizeof(frame));
frame[0] = frame[1] = frame[2] = frame[3] = frame[4] = frame[5] = 0xff;
memcpy(frame + 6, mac, 6);
frame[12] = ETH_P_ARP / 256;
frame[13] = ETH_P_ARP % 256;
memcpy (frame + 14, &hdr, sizeof(hdr));
// send packet
int len;
if ((len = sendto (sock, frame, 14 + sizeof(ArpHdr), 0, (struct sockaddr *) &addr, sizeof (addr))) <= 0)
errExit("send");
//printf("send %d bytes to %d.%d.%d.%d\n", len, PRINT_IP(dest));
fflush(0);
dest++;
}
if (FD_ISSET(sock, &rfds)) {
// read the incoming packet
int len = recvfrom(sock, frame, ETH_FRAME_LEN, 0, NULL, NULL);
if (len < 0) {
perror("recvfrom");
}
// parse the incoming packet
if ((unsigned int) len < 14 + sizeof(ArpHdr))
continue;
// look only at ARP packets
if (frame[12] != (ETH_P_ARP / 256) || frame[13] != (ETH_P_ARP % 256))
continue;
ArpHdr hdr;
memcpy(&hdr, frame + 14, sizeof(ArpHdr));
if (hdr.opcode == htons(2)) {
// check my mac and my address
if (memcmp(mac, hdr.target_mac, 6) != 0)
continue;
uint32_t ip;
memcpy(&ip, hdr.target_ip, 4);
if (ip != src)
continue;
memcpy(&ip, hdr.sender_ip, 4);
ip = ntohl(ip);
if (ip == last_ip) // filter duplicates
continue;
last_ip = ip;
// printing
if (header_printed == 0) {
printf(" Network scan:\n");
header_printed = 1;
}
printf(" %02x:%02x:%02x:%02x:%02x:%02x\t%d.%d.%d.%d\n",
PRINT_MAC(hdr.sender_mac), PRINT_IP(ip));
}
}
}
close(sock);
}

View file

@ -36,5 +36,14 @@ void net_bridge_add_interface(const char *bridge, const char *dev);
void net_if_up(const char *ifname);
int net_get_mtu(const char *ifname);
void net_set_mtu(const char *ifname, int mtu);
void net_ifprint(int scan);
int net_get_mac(const char *ifname, unsigned char mac[6]);
void net_if_ip(const char *ifname, uint32_t ip, uint32_t mask, int mtu);
int net_if_mac(const char *ifname, const unsigned char mac[6]);
void net_if_ip6(const char *ifname, const char *addr6);
// arp.c
void arp_scan(const char *dev, uint32_t ifip, uint32_t ifmask);
#endif

View file

@ -180,4 +180,216 @@ void net_set_mtu(const char *ifname, int mtu) {
close(s);
}
// scan interfaces in current namespace and print IP address/mask for each interface
void net_ifprint(int scan) {
uint32_t ip;
uint32_t mask;
struct ifaddrs *ifaddr, *ifa;
if (getifaddrs(&ifaddr) == -1)
errExit("getifaddrs");
printf("%-17.17s%-19.19s%-17.17s%-17.17s%-6.6s\n",
"Interface", "MAC", "IP", "Mask", "Status");
// walk through the linked list
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
if (ifa->ifa_addr == NULL)
continue;
if (ifa->ifa_addr->sa_family == AF_INET) {
struct sockaddr_in *si = (struct sockaddr_in *) ifa->ifa_netmask;
mask = ntohl(si->sin_addr.s_addr);
si = (struct sockaddr_in *) ifa->ifa_addr;
ip = ntohl(si->sin_addr.s_addr);
// interface status
char *status;
if (ifa->ifa_flags & IFF_RUNNING && ifa->ifa_flags & IFF_UP)
status = "UP";
else
status = "DOWN";
// ip address and mask
char ipstr[30];
sprintf(ipstr, "%d.%d.%d.%d", PRINT_IP(ip));
char maskstr[30];
sprintf(maskstr, "%d.%d.%d.%d", PRINT_IP(mask));
// mac address
unsigned char mac[6];
net_get_mac(ifa->ifa_name, mac);
char macstr[30];
if (strcmp(ifa->ifa_name, "lo") == 0)
macstr[0] = '\0';
else
sprintf(macstr, "%02x:%02x:%02x:%02x:%02x:%02x", PRINT_MAC(mac));
// print
printf("%-17.17s%-19.19s%-17.17s%-17.17s%-6.6s\n",
ifa->ifa_name, macstr, ipstr, maskstr, status);
// network scanning
if (!scan) // scanning disabled
continue;
if (strcmp(ifa->ifa_name, "lo") == 0) // no loopbabck scanning
continue;
if (mask2bits(mask) < 16) // not scanning large networks
continue;
if (!ip) // if not configured
continue;
// only if the interface is up and running
if (ifa->ifa_flags & IFF_RUNNING && ifa->ifa_flags & IFF_UP)
arp_scan(ifa->ifa_name, ip, mask);
}
}
freeifaddrs(ifaddr);
}
int net_get_mac(const char *ifname, unsigned char mac[6]) {
struct ifreq ifr;
int sock;
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
errExit("socket");
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
if (ioctl(sock, SIOCGIFHWADDR, &ifr) == -1)
errExit("ioctl");
memcpy(mac, ifr.ifr_hwaddr.sa_data, 6);
close(sock);
return 0;
}
// configure interface ipv4 address
void net_if_ip(const char *ifname, uint32_t ip, uint32_t mask, int mtu) {
if (strlen(ifname) > IFNAMSIZ) {
fprintf(stderr, "Error: invalid network device name %s\n", ifname);
exit(1);
}
int sock = socket(AF_INET,SOCK_DGRAM,0);
if (sock < 0)
errExit("socket");
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
ifr.ifr_addr.sa_family = AF_INET;
((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr = htonl(ip);
if (ioctl( sock, SIOCSIFADDR, &ifr ) < 0) {
close(sock);
errExit("ioctl");
}
if (ip != 0) {
((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr = htonl(mask);
if (ioctl( sock, SIOCSIFNETMASK, &ifr ) < 0) {
close(sock);
errExit("ioctl");
}
}
// configure mtu
if (mtu > 0) {
ifr.ifr_mtu = mtu;
if (ioctl( sock, SIOCSIFMTU, &ifr ) < 0) {
close(sock);
errExit("ioctl");
}
}
close(sock);
usleep(10000); // sleep 10ms
}
int net_if_mac(const char *ifname, const unsigned char mac[6]) {
struct ifreq ifr;
int sock;
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
errExit("socket");
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
memcpy(ifr.ifr_hwaddr.sa_data, mac, 6);
if (ioctl(sock, SIOCSIFHWADDR, &ifr) == -1)
errExit("ioctl");
close(sock);
return 0;
}
// configure interface ipv6 address
// ex: firejail --net=eth0 --ip6=2001:0db8:0:f101::1/64
struct ifreq6 {
struct in6_addr ifr6_addr;
uint32_t ifr6_prefixlen;
unsigned int ifr6_ifindex;
};
void net_if_ip6(const char *ifname, const char *addr6) {
if (strchr(addr6, ':') == NULL) {
fprintf(stderr, "Error fnet: invalid IPv6 address %s\n", addr6);
exit(1);
}
// extract prefix
unsigned long prefix;
char *ptr;
if ((ptr = strchr(addr6, '/'))) {
prefix = atol(ptr + 1);
if (prefix > 128) {
fprintf(stderr, "Error fnet: invalid prefix for IPv6 address %s\n", addr6);
exit(1);
}
*ptr = '\0'; // mark the end of the address
}
else
prefix = 128;
// extract address
struct sockaddr_in6 sin6;
memset(&sin6, 0, sizeof(sin6));
sin6.sin6_family = AF_INET6;
int rv = inet_pton(AF_INET6, addr6, sin6.sin6_addr.s6_addr);
if (rv <= 0) {
fprintf(stderr, "Error fnet: invalid IPv6 address %s\n", addr6);
exit(1);
}
// open socket
int sock = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
if (sock < 0) {
fprintf(stderr, "Error fnet: IPv6 is not supported on this system\n");
exit(1);
}
// find interface index
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
ifr.ifr_addr.sa_family = AF_INET;
if (ioctl(sock, SIOGIFINDEX, &ifr) < 0) {
perror("ioctl SIOGIFINDEX");
exit(1);
}
// configure address
struct ifreq6 ifr6;
memset(&ifr6, 0, sizeof(ifr6));
ifr6.ifr6_prefixlen = prefix;
ifr6.ifr6_ifindex = ifr.ifr_ifindex;
memcpy((char *) &ifr6.ifr6_addr, (char *) &sin6.sin6_addr, sizeof(struct in6_addr));
if (ioctl(sock, SIOCSIFADDR, &ifr6) < 0) {
perror("ioctl SIOCSIFADDR");
exit(1);
}
close(sock);
}

View file

@ -24,12 +24,18 @@ static void usage(void) {
printf("\tfnet create veth dev1 dev2 bridge child\n");
printf("\tfnet create macvlan dev parent child\n");
printf("\tfnet moveif dev proc\n");
printf("\tfnet printif\n");
printf("\tfnet printif scan\n");
printf("\tfnet config interface dev ip mask mtu\n");
printf("\tfnet config mac addr\n");
printf("\tfnet config ipv6 dev ipn");
printf("\tfmet ifup dev\n");
}
int main(int argc, char **argv) {
#if 0
{
system("cat /proc/self/status");
//system("cat /proc/self/status");
int i;
for (i = 0; i < argc; i++)
printf("*%s* ", argv[i]);
@ -45,22 +51,49 @@ printf("\n");
usage();
return 0;
}
else if (argc == 3 && strcmp(argv[1], "ifup") == 0) {
net_if_up(argv[2]);
}
else if (argc == 2 && strcmp(argv[1], "printif") == 0) {
net_ifprint(0);
}
else if (argc == 3 && strcmp(argv[1], "printif") == 0 && strcmp(argv[2], "scan") == 0) {
net_ifprint(1);
}
else if (argc == 7 && strcmp(argv[1], "create") == 0 && strcmp(argv[2], "veth") == 0) {
// create veth pair and move one end in the the namespace
net_create_veth(argv[3], argv[4], atoi(argv[6]));
// connect the ohter veth end to the bridge ...
net_bridge_add_interface(argv[5], argv[3]);
// ... and bring it up
net_if_up(argv[3]);
}
else if (argc == 6 && strcmp(argv[1], "create") == 0 && strcmp(argv[2], "macvlan") == 0) {
net_create_macvlan(argv[3], argv[4], atoi(argv[5]));
}
else if (argc == 7 && strcmp(argv[1], "config") == 0 && strcmp(argv[2], "interface") == 0) {
char *dev = argv[3];
uint32_t ip = (uint32_t) atoll(argv[4]);
uint32_t mask = (uint32_t) atoll(argv[5]);
int mtu = atoi(argv[6]);
// configure interface
net_if_ip(dev, ip, mask, mtu);
// ... and bring it up
net_if_up(dev);
}
else if (argc == 5 && strcmp(argv[1], "config") == 0 && strcmp(argv[2], "mac") == 0) {
unsigned char mac[6];
if (atomac(argv[4], mac)) {
fprintf(stderr, "Error fnet: invalid mac address %s\n", argv[4]);
}
net_if_mac(argv[3], mac);
}
else if (argc == 4 && strcmp(argv[1], "moveif") == 0) {
net_move_interface(argv[2], atoi(argv[3]));
}
else if (argc == 5 && strcmp(argv[1], "config") == 0 && strcmp(argv[2], "ipv6") == 0) {
net_if_ip6(argv[3], argv[4]);
}
else {
fprintf(stderr, "Error fnet: invalid arguments\n");
return 1;

View file

@ -9,15 +9,15 @@ static void usage(void) {
}
int main(int argc, char **argv) {
//#if 0
#if 0
{
//system("cat /proc/self/status");
system("cat /proc/self/status");
int i;
for (i = 0; i < argc; i++)
printf("*%s* ", argv[i]);
printf("\n");
}
//#endif
#endif
if (argc < 2)
return 1;