mirror of
https://github.com/netblue30/firejail.git
synced 2026-05-15 14:16:14 -06:00
major cleanup
This commit is contained in:
parent
2ef5a3dc71
commit
f898290fd7
30 changed files with 869 additions and 889 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -19,4 +19,5 @@ src/ftee/ftee
|
|||
src/tags
|
||||
src/faudit/faudit
|
||||
src/fnet/fnet
|
||||
src/fseccomp/fseccomp
|
||||
uids.h
|
||||
|
|
|
|||
2
README
2
README
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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, ...);
|
||||
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
110
src/firejail/preproc.c
Normal 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);
|
||||
}
|
||||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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] */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
208
src/fnet/arp.c
Normal 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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue