Example #1
0
// keep filter for seccomp option
int seccomp_filter_keep(void) {
	filter_init();

	// these 4 syscalls are used by firejail after the seccomp filter is initialized
	filter_add_whitelist(SYS_setuid);
	filter_add_whitelist(SYS_setgid);
	filter_add_whitelist(SYS_setgroups);
	filter_add_whitelist(SYS_dup);
	
	// apply keep list
	if (arg_seccomp_list_keep) {
		if (syscall_check_list(arg_seccomp_list_keep, filter_add_whitelist)) {
			exechelp_logerrv("firejail", FIREJAIL_ERROR, "Error: cannot load seccomp filter\n");
			exit(1);
		}
	}
	
	filter_end_whitelist();
	if (arg_debug)
		filter_debug();

	// save seccomp filter in  /tmp/firejail/mnt/seccomp
	// in order to use it in --join operations
	write_seccomp_file();


	struct sock_fprog prog = {
		.len = sfilter_index,
		.filter = sfilter,
	};

	if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) || prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
		exechelp_logerrv("firejail", FIREJAIL_WARNING, "Error: seccomp disabled, it requires a Linux kernel version 3.5 or newer.\n");
		return 1;
	}
	else if (arg_debug) {
		printf("seccomp enabled\n");
	}
	
	return 0;
}
Example #2
0
// errno filter for seccomp option
int seccomp_filter_errno(void) {
	int i;
	int higest_errno = errno_highest_nr();
	filter_init();

	// apply errno list

	for (i = 0; i < higest_errno; i++) {
		if (cfg.seccomp_list_errno[i]) {
			if (syscall_check_list(cfg.seccomp_list_errno[i], filter_add_errno, i)) {
				fprintf(stderr, "Error: cannot load seccomp filter\n");
				exit(1);
			}
		}
	}

	filter_end_blacklist();
	if (arg_debug)
		filter_debug();

	// save seccomp filter in  /tmp/firejail/mnt/seccomp
	// in order to use it in --join operations
	write_seccomp_file();

	struct sock_fprog prog = {
		.len = sfilter_index,
		.filter = sfilter,
	};

	if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) || prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
		fprintf(stderr, "Warning: seccomp disabled, it requires a Linux kernel version 3.5 or newer.\n");
		return 1;
	}
	else if (arg_debug) {
		printf("seccomp enabled\n");
	}

	return 0;
}
Example #3
0
// drop filter for seccomp option
int seccomp_filter_drop(void) {
	filter_init();
	
	// default seccomp
	if (arg_seccomp_list_drop == NULL) {
#ifdef SYS_mount		
		filter_add_blacklist(SYS_mount);
#endif
#ifdef SYS_umount2		
		filter_add_blacklist(SYS_umount2);
#endif
#ifdef SYS_ptrace 		
		filter_add_blacklist(SYS_ptrace);
#endif
#ifdef SYS_kexec_load		
		filter_add_blacklist(SYS_kexec_load);
#endif
#ifdef SYS_open_by_handle_at		
		filter_add_blacklist(SYS_open_by_handle_at);
#endif
#ifdef SYS_init_module		
		filter_add_blacklist(SYS_init_module);
#endif
#ifdef SYS_finit_module // introduced in 2013
		filter_add_blacklist(SYS_finit_module);
#endif
#ifdef SYS_delete_module		
		filter_add_blacklist(SYS_delete_module);
#endif
#ifdef SYS_iopl		
		filter_add_blacklist(SYS_iopl);
#endif
#ifdef 	SYS_ioperm	
		filter_add_blacklist(SYS_ioperm);
#endif
#ifdef SYS_ni_syscall // new io permisions call on arm devices
		filter_add_blacklist(SYS_ni_syscall);
#endif
#ifdef SYS_swapon		
		filter_add_blacklist(SYS_swapon);
#endif
#ifdef SYS_swapoff		
		filter_add_blacklist(SYS_swapoff);
#endif
#ifdef SYS_syslog		
		filter_add_blacklist(SYS_syslog);
#endif
#ifdef SYS_process_vm_readv		
		filter_add_blacklist(SYS_process_vm_readv);
#endif
#ifdef SYS_process_vm_writev		
		filter_add_blacklist(SYS_process_vm_writev);
#endif

// mknod removed in 0.9.29
//#ifdef SYS_mknod		
//		filter_add_blacklist(SYS_mknod);
//#endif
		
		// new syscalls in 0.9,23		
#ifdef SYS_sysfs		
		filter_add_blacklist(SYS_sysfs);
#endif
#ifdef SYS__sysctl	
		filter_add_blacklist(SYS__sysctl);
#endif
#ifdef SYS_adjtimex		
		filter_add_blacklist(SYS_adjtimex);
#endif
#ifdef 	SYS_clock_adjtime	
		filter_add_blacklist(SYS_clock_adjtime);
#endif
#ifdef SYS_lookup_dcookie		
		filter_add_blacklist(SYS_lookup_dcookie);
#endif
#ifdef 	SYS_perf_event_open	
		filter_add_blacklist(SYS_perf_event_open);
#endif
#ifdef	SYS_fanotify_init 	
		filter_add_blacklist(SYS_fanotify_init);
#endif
#ifdef SYS_kcmp
		filter_add_blacklist(SYS_kcmp);
#endif
	}

	// default seccomp filter with additional drop list
	if (arg_seccomp_list && arg_seccomp_list_drop == NULL) {
		if (syscall_check_list(arg_seccomp_list, filter_add_blacklist)) {
			exechelp_logerrv("firejail", FIREJAIL_ERROR, "Error: cannot load seccomp filter\n");
			exit(1);
		}
	}
	// drop list
	else if (arg_seccomp_list == NULL && arg_seccomp_list_drop) {
		if (syscall_check_list(arg_seccomp_list_drop, filter_add_blacklist)) {
			exechelp_logerrv("firejail", FIREJAIL_ERROR, "Error: cannot load seccomp filter\n");
			exit(1);
		}
	}
	
	
	filter_end_blacklist();
	if (arg_debug)
		filter_debug();

	// save seccomp filter in  /tmp/firejail/mnt/seccomp
	// in order to use it in --join operations
	write_seccomp_file();


	struct sock_fprog prog = {
		.len = sfilter_index,
		.filter = sfilter,
	};

	if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) || prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
		exechelp_logerrv("firejail", FIREJAIL_WARNING, "Error: seccomp disabled, it requires a Linux kernel version 3.5 or newer.\n");
		return 1;
	}
	else if (arg_debug) {
		printf("seccomp enabled\n");
	}
	
	return 0;
}
Example #4
0
// i386 filter installed on amd64 architectures
void seccomp_filter_32(void) {
	// hardcoded syscall values
	struct sock_filter filter[] = {
		VALIDATE_ARCHITECTURE_32,
		EXAMINE_SYSCALL,
		BLACKLIST(21), // mount
		BLACKLIST(52), // umount2
		BLACKLIST(26), // ptrace
		BLACKLIST(283), // kexec_load
		BLACKLIST(342), // open_by_handle_at
		BLACKLIST(128), // init_module
		BLACKLIST(350), // finit_module
		BLACKLIST(129), // delete_module
		BLACKLIST(110), // iopl
		BLACKLIST(101), // ioperm
		BLACKLIST(87), // swapon
		BLACKLIST(115), // swapoff
		BLACKLIST(103), // syslog
		BLACKLIST(347), // process_vm_readv
		BLACKLIST(348), // process_vm_writev
		BLACKLIST(135), // sysfs
		BLACKLIST(149), // _sysctl
		BLACKLIST(124), // adjtimex
		BLACKLIST(343), // clock_adjtime
		BLACKLIST(253), // lookup_dcookie
		BLACKLIST(336), // perf_event_open
		BLACKLIST(338), // fanotify_init
		BLACKLIST(349), // kcmp
		BLACKLIST(286), // add_key
		BLACKLIST(287), // request_key
		BLACKLIST(288), // keyctl
		BLACKLIST(86), // uselib
		BLACKLIST(51), // acct
		BLACKLIST(123), // modify_ldt
		BLACKLIST(217), // pivot_root
		BLACKLIST(245), // io_setup
		BLACKLIST(246), // io_destroy
		BLACKLIST(247), // io_getevents
		BLACKLIST(248), // io_submit
		BLACKLIST(249), // io_cancel
		BLACKLIST(257), // remap_file_pages
		BLACKLIST(274), // mbind
		BLACKLIST(275), // get_mempolicy
		BLACKLIST(276), // set_mempolicy
		BLACKLIST(294), // migrate_pages
		BLACKLIST(317), // move_pages
		BLACKLIST(316), // vmsplice
		BLACKLIST(61),  // chroot
		BLACKLIST(88), // reboot
		BLACKLIST(169), // nfsservctl
		BLACKLIST(130), // get_kernel_syms
		RETURN_ALLOW
	};

	struct sock_fprog prog = {
		.len = (unsigned short)(sizeof(filter) / sizeof(filter[0])),
		.filter = filter,
	};

	if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) || prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
		;
	}
	else if (arg_debug) {
		printf("Dual i386/amd64 seccomp filter configured\n");
	}
}

// amd64 filter installed on i386 architectures
void seccomp_filter_64(void) {
	// hardcoded syscall values
	struct sock_filter filter[] = {
		VALIDATE_ARCHITECTURE_64,
		EXAMINE_SYSCALL,
		BLACKLIST(165), // mount
		BLACKLIST(166), // umount2
		BLACKLIST(101), // ptrace
		BLACKLIST(246), // kexec_load
		BLACKLIST(304), // open_by_handle_at
		BLACKLIST(175), // init_module
		BLACKLIST(313), // finit_module
		BLACKLIST(176), // delete_module
		BLACKLIST(172), // iopl
		BLACKLIST(173), // ioperm
		BLACKLIST(167), // swapon
		BLACKLIST(168), // swapoff
		BLACKLIST(103), // syslog
		BLACKLIST(310), // process_vm_readv
		BLACKLIST(311), // process_vm_writev
		BLACKLIST(139), // sysfs
		BLACKLIST(156), // _sysctl
		BLACKLIST(159), // adjtimex
		BLACKLIST(305), // clock_adjtime
		BLACKLIST(212), // lookup_dcookie
		BLACKLIST(298), // perf_event_open
		BLACKLIST(300), // fanotify_init
		BLACKLIST(312), // kcmp
		BLACKLIST(248), // add_key
		BLACKLIST(249), // request_key
		BLACKLIST(250), // keyctl
		BLACKLIST(134), // uselib
		BLACKLIST(163), // acct
		BLACKLIST(154), // modify_ldt
		BLACKLIST(155), // pivot_root
		BLACKLIST(206), // io_setup
		BLACKLIST(207), // io_destroy
		BLACKLIST(208), // io_getevents
		BLACKLIST(209), // io_submit
		BLACKLIST(210), // io_cancel
		BLACKLIST(216), // remap_file_pages
		BLACKLIST(237), // mbind
		BLACKLIST(239), // get_mempolicy
		BLACKLIST(238), // set_mempolicy
		BLACKLIST(256), // migrate_pages
		BLACKLIST(279), // move_pages
		BLACKLIST(278), // vmsplice
		BLACKLIST(161), // chroot
		BLACKLIST(184), // tuxcall
		BLACKLIST(169), // reboot
		BLACKLIST(180), // nfsservctl
		BLACKLIST(177), // get_kernel_syms
		RETURN_ALLOW
	};

	struct sock_fprog prog = {
		.len = (unsigned short)(sizeof(filter) / sizeof(filter[0])),
		.filter = filter,
	};

	if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) || prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
		;
	}
	else if (arg_debug) {
		printf("Dual i386/amd64 seccomp filter configured\n");
	}
}


// drop filter for seccomp option
int seccomp_filter_drop(int enforce_seccomp) {
	filter_init();
	
	// default seccomp
	if (cfg.seccomp_list_drop == NULL) {
#if defined(__x86_64__)
		seccomp_filter_32();
#endif
#if defined(__i386__)
		seccomp_filter_64();
#endif

#ifdef SYS_mount		
		filter_add_blacklist(SYS_mount, 0);
#endif
#ifdef SYS_umount2		
		filter_add_blacklist(SYS_umount2, 0);
#endif
#ifdef SYS_ptrace 		
		filter_add_blacklist(SYS_ptrace, 0);
#endif
#ifdef SYS_kexec_load		
		filter_add_blacklist(SYS_kexec_load, 0);
#endif
#ifdef SYS_kexec_file_load		
		filter_add_blacklist(SYS_kexec_file_load, 0);
#endif
#ifdef SYS_open_by_handle_at		
		filter_add_blacklist(SYS_open_by_handle_at, 0);
#endif
#ifdef SYS_init_module		
		filter_add_blacklist(SYS_init_module, 0);
#endif
#ifdef SYS_finit_module // introduced in 2013
		filter_add_blacklist(SYS_finit_module, 0);
#endif
#ifdef SYS_delete_module		
		filter_add_blacklist(SYS_delete_module, 0);
#endif
#ifdef SYS_iopl		
		filter_add_blacklist(SYS_iopl, 0);
#endif
#ifdef 	SYS_ioperm	
		filter_add_blacklist(SYS_ioperm, 0);
#endif
#ifdef SYS_ni_syscall // new io permissions call on arm devices
		filter_add_blacklist(SYS_ni_syscall, 0);
#endif
#ifdef SYS_swapon		
		filter_add_blacklist(SYS_swapon, 0);
#endif
#ifdef SYS_swapoff		
		filter_add_blacklist(SYS_swapoff, 0);
#endif
#ifdef SYS_syslog		
		filter_add_blacklist(SYS_syslog, 0);
#endif
#ifdef SYS_process_vm_readv		
		filter_add_blacklist(SYS_process_vm_readv, 0);
#endif
#ifdef SYS_process_vm_writev		
		filter_add_blacklist(SYS_process_vm_writev, 0);
#endif

// mknod removed in 0.9.29 - it brakes Zotero extension
//#ifdef SYS_mknod		
//		filter_add_blacklist(SYS_mknod, 0);
//#endif
		
		// new syscalls in 0.9,23		
#ifdef SYS_sysfs		
		filter_add_blacklist(SYS_sysfs, 0);
#endif
#ifdef SYS__sysctl	
		filter_add_blacklist(SYS__sysctl, 0);
#endif
#ifdef SYS_adjtimex		
		filter_add_blacklist(SYS_adjtimex, 0);
#endif
#ifdef 	SYS_clock_adjtime	
		filter_add_blacklist(SYS_clock_adjtime, 0);
#endif
#ifdef SYS_lookup_dcookie		
		filter_add_blacklist(SYS_lookup_dcookie, 0);
#endif
#ifdef 	SYS_perf_event_open	
		filter_add_blacklist(SYS_perf_event_open, 0);
#endif
#ifdef	SYS_fanotify_init 	
		filter_add_blacklist(SYS_fanotify_init, 0);
#endif
#ifdef SYS_kcmp
		filter_add_blacklist(SYS_kcmp, 0);
#endif

// 0.9.32
#ifdef SYS_add_key
		filter_add_blacklist(SYS_add_key, 0);
#endif
#ifdef SYS_request_key
		filter_add_blacklist(SYS_request_key, 0);
#endif
#ifdef SYS_keyctl
		filter_add_blacklist(SYS_keyctl, 0);
#endif
#ifdef SYS_uselib
		filter_add_blacklist(SYS_uselib, 0);
#endif
#ifdef SYS_acct
		filter_add_blacklist(SYS_acct, 0);
#endif
#ifdef SYS_modify_ldt
		filter_add_blacklist(SYS_modify_ldt, 0);
#endif
	//#ifdef SYS_unshare
	//		filter_add_blacklist(SYS_unshare, 0);
	//#endif
#ifdef SYS_pivot_root
		filter_add_blacklist(SYS_pivot_root, 0);
#endif
	//#ifdef SYS_quotactl
	//		filter_add_blacklist(SYS_quotactl, 0);
	//#endif
#ifdef SYS_io_setup
		filter_add_blacklist(SYS_io_setup, 0);
#endif
#ifdef SYS_io_destroy
		filter_add_blacklist(SYS_io_destroy, 0);
#endif
#ifdef SYS_io_getevents
		filter_add_blacklist(SYS_io_getevents, 0);
#endif
#ifdef SYS_io_submit
		filter_add_blacklist(SYS_io_submit, 0);
#endif
#ifdef SYS_io_cancel
		filter_add_blacklist(SYS_io_cancel, 0);
#endif
#ifdef SYS_remap_file_pages
		filter_add_blacklist(SYS_remap_file_pages, 0);
#endif
#ifdef SYS_mbind
		filter_add_blacklist(SYS_mbind, 0);
#endif
#ifdef SYS_get_mempolicy
		filter_add_blacklist(SYS_get_mempolicy, 0);
#endif
#ifdef SYS_set_mempolicy
		filter_add_blacklist(SYS_set_mempolicy, 0);
#endif
#ifdef SYS_migrate_pages
		filter_add_blacklist(SYS_migrate_pages, 0);
#endif
#ifdef SYS_move_pages
		filter_add_blacklist(SYS_move_pages, 0);
#endif
#ifdef SYS_vmsplice
		filter_add_blacklist(SYS_vmsplice, 0);
#endif
#ifdef SYS_chroot
		filter_add_blacklist(SYS_chroot, 0);
#endif
	//#ifdef SYS_set_robust_list
	//		filter_add_blacklist(SYS_set_robust_list, 0);
	//#endif
	//#ifdef SYS_get_robust_list
	//		filter_add_blacklist(SYS_get_robust_list, 0);
	//#endif

 // CHECK_SECCOMP(seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EPERM), SCMP_SYS(clone), 1,
 //     SCMP_A0(SCMP_CMP_MASKED_EQ, CLONE_NEWUSER, CLONE_NEWUSER)));

// 0.9.39
#ifdef SYS_tuxcall
		filter_add_blacklist(SYS_tuxcall, 0);
#endif
#ifdef SYS_reboot
		filter_add_blacklist(SYS_reboot, 0);
#endif
#ifdef SYS_nfsservctl
		filter_add_blacklist(SYS_nfsservctl, 0);
#endif
#ifdef SYS_get_kernel_syms
		filter_add_blacklist(SYS_get_kernel_syms, 0);
#endif
	}

	// default seccomp filter with additional drop list
	if (cfg.seccomp_list && cfg.seccomp_list_drop == NULL) {
		if (syscall_check_list(cfg.seccomp_list, filter_add_blacklist, 0)) {
			fprintf(stderr, "Error: cannot load seccomp filter\n");
			exit(1);
		}
	}
	// drop list
	else if (cfg.seccomp_list == NULL && cfg.seccomp_list_drop) {
		if (syscall_check_list(cfg.seccomp_list_drop, filter_add_blacklist, 0)) {
			fprintf(stderr, "Error: cannot load seccomp filter\n");
			exit(1);
		}
	}
	
	
	filter_end_blacklist();
	if (arg_debug)
		filter_debug();

	// save seccomp filter in  /tmp/firejail/mnt/seccomp
	// in order to use it in --join operations
	write_seccomp_file();


	struct sock_fprog prog = {
		.len = sfilter_index,
		.filter = sfilter,
	};

	if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) || prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
		if (enforce_seccomp) {
			fprintf(stderr, "Error: a seccomp-enabled Linux kernel is required, exiting...\n");
			exit(1);
		}
		else
			fprintf(stderr, "Warning: seccomp disabled, it requires a Linux kernel version 3.5 or newer.\n");

		return 1;
	}
	
	return 0;
}

// keep filter for seccomp option
int seccomp_filter_keep(void) {
	filter_init();

	// these 4 syscalls are used by firejail after the seccomp filter is initialized
	filter_add_whitelist(SYS_setuid, 0);
	filter_add_whitelist(SYS_setgid, 0);
	filter_add_whitelist(SYS_setgroups, 0);
	filter_add_whitelist(SYS_dup, 0);
	
	// apply keep list
	if (cfg.seccomp_list_keep) {
		if (syscall_check_list(cfg.seccomp_list_keep, filter_add_whitelist, 0)) {
			fprintf(stderr, "Error: cannot load seccomp filter\n");
			exit(1);
		}
	}
	
	filter_end_whitelist();
	if (arg_debug)
		filter_debug();

	// save seccomp filter in  /tmp/firejail/mnt/seccomp
	// in order to use it in --join operations
	write_seccomp_file();


	struct sock_fprog prog = {
		.len = sfilter_index,
		.filter = sfilter,
	};

	if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) || prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
		fprintf(stderr, "Warning: seccomp disabled, it requires a Linux kernel version 3.5 or newer.\n");
		return 1;
	}
	else if (arg_debug) {
		printf("seccomp enabled\n");
	}
	
	return 0;
}
Example #5
0
// drop filter for seccomp option
int seccomp_filter_drop(void) {
	filter_init();
	
	// default seccomp
	if (arg_seccomp_list_drop == NULL) {
		filter_add_blacklist(SYS_mount);
		filter_add_blacklist(SYS_umount2);
		filter_add_blacklist(SYS_ptrace);
		filter_add_blacklist(SYS_kexec_load);
		filter_add_blacklist(SYS_open_by_handle_at);
		filter_add_blacklist(SYS_init_module);
#ifdef SYS_finit_module // introduced in 2013
		filter_add_blacklist(SYS_finit_module);
#endif
		filter_add_blacklist(SYS_delete_module);
		filter_add_blacklist(SYS_iopl);
		filter_add_blacklist(SYS_ioperm);
		filter_add_blacklist(SYS_swapon);
		filter_add_blacklist(SYS_swapoff);
		filter_add_blacklist(SYS_syslog);
		filter_add_blacklist(SYS_process_vm_readv);
		filter_add_blacklist(SYS_process_vm_writev);
		filter_add_blacklist(SYS_mknod);
		
		// new syscalls in 0.9,23		
		filter_add_blacklist(SYS_sysfs);
		filter_add_blacklist(SYS__sysctl);
		filter_add_blacklist(SYS_adjtimex);
		filter_add_blacklist(SYS_clock_adjtime);
		filter_add_blacklist(SYS_lookup_dcookie);
		filter_add_blacklist(SYS_perf_event_open);
		filter_add_blacklist(SYS_fanotify_init);
#ifdef SYS_kcmp // todo: check it on newer distros; it is not in Debian 7	
		filter_add_blacklist(SYS_kcmp);
#endif
	}

	// default seccomp filter with additional drop list
	if (arg_seccomp_list && arg_seccomp_list_drop == NULL) {
		if (syscall_check_list(arg_seccomp_list, filter_add_blacklist)) {
			fprintf(stderr, "Error: cannot load seccomp filter\n");
			exit(1);
		}
	}
	// drop list
	else if (arg_seccomp_list == NULL && arg_seccomp_list_drop) {
		if (syscall_check_list(arg_seccomp_list_drop, filter_add_blacklist)) {
			fprintf(stderr, "Error: cannot load seccomp filter\n");
			exit(1);
		}
	}
	
	
	filter_end_blacklist();
	if (arg_debug)
		filter_debug();

	// save seccomp filter in  /tmp/firejail/mnt/seccomp
	// in order to use it in --join operations
	write_seccomp_file();


	struct sock_fprog prog = {
		.len = sfilter_index,
		.filter = sfilter,
	};

	if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) || prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
		fprintf(stderr, "Warning: seccomp disabled, it requires a Linux kernel version 3.5 or newer.\n");
		return 1;
	}
	else if (arg_debug) {
		printf("seccomp enabled\n");
	}
	
	return 0;
}
Example #6
0
// check profile line; if line == 0, this was generated from a command line option
// return 1 if the command is to be added to the linked list of profile commands
// return 0 if the command was already executed inside the function
int profile_check_line(char *ptr, int lineno) {
	// seccomp, caps, private
	if (strcmp(ptr, "seccomp") == 0) {
		arg_seccomp = 1;
		return 0;
	}
	else if (strcmp(ptr, "caps") == 0) {
		arg_caps = 1;
		return 0;
	}
	else if (strcmp(ptr, "private") == 0) {
		arg_private = 1;
		return 0;
	}
	
	// seccomp list
	if (strncmp(ptr, "seccomp ", 8) == 0) {
		arg_seccomp = 1;
#ifdef HAVE_SECCOMP
		arg_seccomp_list = strdup(ptr + 8);
		if (!arg_seccomp_list)
			errExit("strdup");
		// verify seccomp list and exit if problems
		if (syscall_check_list(arg_seccomp_list, NULL))
			exit(1);
#endif
		return 0;
	}
	
	// private directory
	if (strncmp(ptr, "private ", 8) == 0) {
		cfg.home_private = ptr + 8;
		check_private_dir();
		arg_private = 1;
		return 0;
	}

	// filesystem bind
	if (strncmp(ptr, "bind ", 5) == 0) {
		if (getuid() != 0) {
			fprintf(stderr, "Error: --bind option is available only if running as root\n");
			exit(1);
		}

		// extract two directories
		char *dname1 = ptr + 5;
		char *dname2 = split_comma(dname1); // this inserts a '0 to separate the two dierctories
		if (dname2 == NULL) {
			fprintf(stderr, "Error: mising second directory for bind\n");
			exit(1);
		}
		
		// check directories
		check_file_name(dname1, lineno);
		check_file_name(dname2, lineno);
		
		// insert comma back
		*(dname2 - 1) = ',';
		return 1;
	}

	// rlimit
	if (strncmp(ptr, "rlimit", 6) == 0) {
		if (strncmp(ptr, "rlimit-nofile ", 14) == 0) {
			ptr += 14;
			if (not_unsigned(ptr)) {
				fprintf(stderr, "Invalid rlimit option on line %d\n", lineno);
				exit(1);
			}
			sscanf(ptr, "%u", &cfg.rlimit_nofile);
			arg_rlimit_nofile = 1;
		}
		else if (strncmp(ptr, "rlimit-nproc ", 13) == 0) {
			ptr += 13;
			if (not_unsigned(ptr)) {
				fprintf(stderr, "Invalid rlimit option on line %d\n", lineno);
				exit(1);
			}
			sscanf(ptr, "%u", &cfg.rlimit_nproc);
			arg_rlimit_nproc = 1;
		}
		else if (strncmp(ptr, "rlimit-fsize ", 13) == 0) {
			ptr += 13;
			if (not_unsigned(ptr)) {
				fprintf(stderr, "Invalid rlimit option on line %d\n", lineno);
				exit(1);
			}
			sscanf(ptr, "%u", &cfg.rlimit_fsize);
			arg_rlimit_fsize = 1;
		}
		else if (strncmp(ptr, "rlimit-sigpending ", 18) == 0) {
			ptr += 18;
			if (not_unsigned(ptr)) {
				fprintf(stderr, "Invalid rlimit option on line %d\n", lineno);
				exit(1);
			}
			sscanf(ptr, "%u", &cfg.rlimit_sigpending);
			arg_rlimit_sigpending = 1;
		}
		else {
			fprintf(stderr, "Invalid rlimit option on line %d\n", lineno);
			exit(1);
		}
		
		return 0;		
	}

	// rest of filesystem
	if (strncmp(ptr, "blacklist ", 10) == 0)
		ptr += 10;
	else if (strncmp(ptr, "read-only ", 10) == 0)
		ptr += 10;
	else if (strncmp(ptr, "tmpfs ", 6) == 0)
		ptr += 6;
	else {
		if (lineno == 0)
			fprintf(stderr, "Error: \"%s\" as a command line option is invalid\n", ptr);
		else
			fprintf(stderr, "Error: line %d in the custom profile is invalid\n", lineno);
		exit(1);
	}

	// some characters just don't belong in filenames
	check_file_name(ptr, lineno);
	return 1;
}