Commit d9156e9f authored by O'Reilly Media, Inc.'s avatar O'Reilly Media, Inc.
Browse files

Initial commit

parents
## Example files for the title:
# SELinux Cookbook, by Sven Vermeulen
[![SELinux Cookbook, by Sven Vermeulen](http://akamaicovers.oreilly.com/images/9781783989676/cat.gif)](https://www.safaribooksonline.com/)
The following applies to example files from material published by O’Reilly Media, Inc. Content from other publishers may include different rules of usage. Please refer to any additional usage rights explained in the actual example files or refer to the publisher’s website.
O'Reilly books are here to help you get your job done. In general, you may use the code in O'Reilly books in your programs and documentation. You do not need to contact us for permission unless you're reproducing a significant portion of the code. For example, writing a program that uses several chunks of code from our books does not require permission. Answering a question by citing our books and quoting example code does not require permission. On the other hand, selling or distributing a CD-ROM of examples from O'Reilly books does require permission. Incorporating a significant amount of example code from our books into your product's documentation does require permission.
We appreciate, but do not require, attribution. An attribution usually includes the title, author, publisher, and ISBN.
If you think your use of code examples falls outside fair use or the permission given here, feel free to contact us at <permissions@oreilly.com>.
Please note that the examples are not production code and have not been carefully testing. They are provided "as-is" and come with no warranty of any kind.
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdarg.h>
#define DEBUG 7
#define INFO 6
#define NOTICE 5
#define WARN 4
#define ERR 3
#define CRIT 2
#define ALERT 1
#define EMERG 0
#ifndef LOGLEVEL
#define LOGLEVEL 4
#endif
#ifdef SELINUX
#include <selinux/selinux.h>
#include <selinux/flask.h>
#include <selinux/av_permissions.h>
#include <selinux/get_context_list.h>
#endif
/* out - Simple output */
void out(int level, char * msg, ...) {
if (level <= LOGLEVEL) {
va_list ap;
printf("%d - ", level);
va_start(ap, msg);
vprintf(msg, ap);
va_end(ap);
};
};
/* selinux_prepare_fork - Initialize context switching
*
* Returns
* - 0 if everything is OK,
* - +1 if the code should continue, even if SELinux wouldn't allow
* (for instance due to permissive mode)
* - -1 if the code should not continue
*/
int selinux_prepare_fork(char * name) {
#ifndef SELINUX
return 0;
#else
char * newcon = 0;
char * curcon = 0;
struct av_decision avd;
int rc;
int permissive = 0;
int dom_permissive = 0;
char * sename = 0;
char * selevel = 0;
/*
* See if SELinux is enabled.
* If not, then we can immediately tell the code
* that everything is OK.
*/
rc = is_selinux_enabled();
if (rc == 0) {
out(DEBUG, "SELinux is not enabled.\n");
return 0;
} else if (rc == -1) {
out(WARN, "Could not check SELinux state (is_selinux_enabled() failed)\n");
return 1;
};
out(DEBUG, "SELinux is enabled.\n");
/*
* See if SELinux is in enforcing mode
* or permissive mode
*/
rc = security_getenforce();
if (rc == 0) {
permissive = 1;
} else if (rc == 1) {
permissive = 0;
} else {
out(WARN, "Could not check SELinux mode (security_getenforce() failed)\n");
}
out(DEBUG, "SELinux mode is %s\n", permissive ? "permissive" : "enforcing");
/*
* Get the current SELinux context of the process.
* Always interesting to log this for end users
* trying to debug a possible issue.
*/
rc = getcon(&curcon);
if (rc) {
out(WARN, "Could not get current SELinux context (getcon() failed)\n");
if (permissive)
return +1;
else
return -1;
};
out(DEBUG, "Currently in SELinux context \"%s\"\n", (char *) curcon);
/*
* Get the SELinux user given the Linux user
* name passed on to this function.
*/
rc = getseuserbyname(name, &sename, &selevel);
if (rc) {
out(WARN, "Could not find SELinux user for Linux user \"%s\" (getseuserbyname() failed)\n", name);
freecon(curcon);
if (permissive)
return +1;
else
return -1;
};
out(DEBUG, "SELinux user for Linux user \"%s\" is \"%s\"\n", name, sename);
/*
* Find out what the context is that this process should transition
* to.
*/
rc = get_default_context(sename, NULL, &newcon);
if (rc) {
out(WARN, "Could not deduce default context for SELinux user \"%s\" given our current context (\"%s\")\n", sename, (char *) curcon);
freecon(curcon);
if (permissive)
return +1;
else
return -1;
};
out(DEBUG, "SELinux context to transition to is \"%s\"\n", (char *) newcon);
/*
* Now let's look if we are allowed to transition to the new context.
* We currently only check the transition access for the process class. However,
* transitioning is a bit more complex (execute rights on target context,
* entrypoint of that context for the new domain, no constraints like target
* domain not being a valid one, MLS constraints, etc.).
*/
rc = security_compute_av_flags(curcon, newcon, SECCLASS_PROCESS, PROCESS__TRANSITION, &avd);
if (rc) {
out(WARN, "Could not deduce rights for transitioning \"%s\" -> \"%s\" (security_compute_av_flags() failed)\n", (char *) curcon, (char *) newcon);
freecon(curcon);
freecon(newcon);
if (permissive)
return +1;
else
return -1;
};
/* Validate the response
*
* We are interested in two things:
* - Is the transition allowed, but also
* - Is the permissive flag set
*
* If the permissive flag is set, then we
* know the current domain is permissive
* (even if the rest of the system is in
* enforcing mode).
*/
if (avd.flags & SELINUX_AVD_FLAGS_PERMISSIVE) {
out(DEBUG, "The SELINUX_AVD_FLAGS_PERMISSIVE flag is set, so domain is permissive.\n");
dom_permissive = 1;
};
if (!(avd.allowed & PROCESS__TRANSITION)) {
// The transition is denied
if (permissive) {
out(DEBUG, "Transition is not allowed by SELinux, but permissive mode is enabled. Continuing.\n");
};
if (dom_permissive) {
out(DEBUG, "Transition is not allowed by SELinux, but domain is in permissive mode. Continuing.\n");
};
if ((permissive == 0) && (dom_permissive == 0)) {
out(WARN, "The domain transition is not allowed and we are not in permissive mode.\n");
freecon(curcon);
freecon(newcon);
return -1;
};
};
/*
* Set the context for the fork (process execution).
*/
rc = setexeccon(newcon);
if (rc) {
out(WARN, "Could not set execution context (setexeccon() failed)\n");
freecon(curcon);
freecon(newcon);
if ((permissive) || (dom_permissive))
return +1;
else
return -1;
};
freecon(newcon);
freecon(curcon);
return 0;
#endif
};
int main(int argc, char * argv[]) {
int rc = 0;
pid_t child;
rc = selinux_prepare_fork(argv[1]);
if (rc < 0) {
out(WARN, "The necessary context change will fail.\n");
// Continuing here would mean that the newly started process
// runs in the wrong context (current context) which might
// be either too privileged, or not privileged enough.
return -1;
} else if (rc > 0) {
out(WARN, "The necessary context change will fail, but permissive mode is active.\n");
};
child = fork();
if (child < 0) {
out(WARN, "fork() failed\n", NULL);
};
if (child == 0) {
int pidrc;
pidrc = execl("/usr/bin/id", "id", "-Z", NULL);
if (pidrc != 0) {
out(WARN, "Command failed with return code %d\n", pidrc);
};
return(0);
} else {
int status;
out(DEBUG, "Child is %d\n", child);
wait(&status);
out(DEBUG, "Child exited with %d\n", status);
};
return 0;
};
# sefindif - Find interface definitions that have a string that matches the
# given regular expression
sefindif() {
REGEXP="$1";
if [ -d ${POLICY_LOCATION}/policy/modules ];
then
pushd ${POLICY_LOCATION}/policy/modules > /dev/null 2>&1;
elif [ -d ${POLICY_LOCATION}/include ];
then
pushd ${POLICY_LOCATION}/include > /dev/null 2>&1;
else
echo "Variable POLICY_LOCATION is not properly defined.";
return 1;
fi
for FILE in */*.if;
do
awk "BEGIN { P=1 } /(interface\(|template\()/ { NAME=\$0; P=0 }; /${REGEXP}/ { if (P==0) {P=1; print NAME}; if (NAME!=\$0) print };" ${FILE} | sed -e "s:^:${FILE}\: :g";
done
popd > /dev/null 2>&1;
}
# seshowif - Show the interface definition
seshowif() {
INTERFACE="$1";
if [ -d ${POLICY_LOCATION}/policy/modules ];
then
pushd ${POLICY_LOCATION}/policy/modules > /dev/null 2>&1;
elif [ -d ${POLICY_LOCATION}/include ];
then
pushd ${POLICY_LOCATION}/include > /dev/null 2>&1;
else
echo "Variable POLICY_LOCATION is not properly defined.";
return 1;
fi
for FILE in */*.if;
do
grep -A 9999 "\(interface(\`${INTERFACE}'\|template(\`${INTERFACE}'\)" ${FILE} | grep -B 9999 -m 1 "^')";
done
popd > /dev/null 2>&1;
}
# sefinddef - Find macro definitions that have a string that matches the given
# regular expression
sefinddef() {
REGEXP="$1";
if [ -d ${POLICY_LOCATION}/policy/support ];
then
pushd ${POLICY_LOCATION}/policy/support > /dev/null 2>&1;
elif [ -d ${POLICY_LOCATION}/include/support ];
then
pushd ${POLICY_LOCATION}/include/support > /dev/null 2>&1;
else
echo "Variable POLICY_LOCATION is not properly defined.";
return 1;
fi
for FILE in *;
do
awk "BEGIN { P=1; } /(define\(\`[^\`]*\`$)/ { NAME=\$0; P=0 }; /${REGEXP}/ { if (P==0) {P=1; print NAME}; if (NAME!=\$0) print };" ${FILE};
done
popd > /dev/null 2>&1;
}
# seshowdef - Show the macro definition
seshowdef() {
MACRONAME="$1";
if [ -d ${POLICY_LOCATION}/policy/support ];
then
pushd ${POLICY_LOCATION}/policy/support > /dev/null 2>&1;
elif [ -d ${POLICY_LOCATION}/include/support ];
then
pushd ${POLICY_LOCATION}/include/support > /dev/null 2>&1;
else
echo "Variable POLICY_LOCATION is not properly defined.";
return 1;
fi
for FILE in *.spt;
do
grep -A 9999 "define(\`${MACRONAME}'" ${FILE} | grep -B 999 -m 1 "')";
done
popd > /dev/null 2>&1;
}
logo.png

10.9 KB

HOME_DIR/\.Skype(/.*)? gen_context(system_u:object_r:skype_home_t,s0)
#
# /opt
#
/opt/skype/skype -- gen_context(system_u:object_r:skype_exec_t,s0)
/opt/bin/skype -- gen_context(system_u:object_r:skype_exec_t,s0)
#
# /usr
#
/usr/bin/skype -- gen_context(system_u:object_r:skype_exec_t,s0)
## <summary>Skype softphone.</summary>
#########################################
## <summary>
## Role access for the skype module.
## </summary>
## <param name="role">
## <summary>
## The role associated with the user domain.
## </summary>
## </param>
## <param name="user_domain">
## <summary>
## The type of the user domain.
## </summary>
## </param>
#
interface(`skype_role',`
gen_require(`
type skype_t, skype_exec_t, skype_tmp_t, skype_home_t;
')
# Allow the skype_t domain for the user role
role $1 types skype_t;
# Allow domain transition for user domain to skype_t
domtrans_pattern($2, skype_exec_t, skype_t)
# Interact with skype process
ps_process_pattern($2, skype_t)
allow $2 skype_t:process { ptrace signal_perms };
# Manage skype file resources
manage_dirs_pattern($2, skype_home_t, skype_home_t)
manage_files_pattern($2, skype_home_t, skype_home_t)
manage_lnk_files_pattern($2, skype_home_t, skype_home_t)
# Allow user to relabel the resources if needed
relabel_dirs_pattern($2, skype_home_t, skype_home_t)
relabel_files_pattern($2, skype_home_t, skype_home_t)
relabel_lnk_files_pattern($2, skype_home_t, skype_home_t)
')
#########################################
## <summary>
## Read skype user configuration
## </summary>
## <param name="domain">
## <summary>
## Domain allowed access
## </summary>
## </param>
#
interface(`skype_read_home',`
gen_require(`
type skype_home_t;
')
allow $1 skype_home_t:dir list_dir_perms;
allow $1 skype_home_t:file read_file_perms;
allow $1 skype_home_t:lnk_file read_lnk_file_perms;
userdom_search_user_home_dirs($1)
')
policy_module(myskype, 0.1)
#########################################
# Declarations
#
## <desc>
## <p>
## Allow skype to use the audio devices
## </p>
## </desc>
gen_tunable(skype_use_audio, false)
## <desc>
## <p>
## Allow skype to use the video devices
## </p>
## </desc>
gen_tunable(skype_use_video, false)
## <desc>
## <p>
## Allow skype to manage user content
## </p>
## </desc>
gen_tunable(skype_manage_user_content, false)
type skype_t;
type skype_exec_t;
userdom_user_application_domain(skype_t, skype_exec_t)
type skype_home_t;
userdom_user_home_content(skype_home_t)
type skype_tmpfs_t;
userdom_user_tmpfs_file(skype_tmpfs_t)
type skype_tmp_t;
userdom_user_tmp_file(skype_tmp_t)
#########################################
# Policy
#
# error while loading shared libraries: cannot restore segment prot after reloc
allow skype_t skype_exec_t:file execmod;
# error 'Permission denied' during 'pthread_create'
allow skype_t skype_t:process execmem;
# Generic privs from avc denials
allow skype_t skype_t:process { getsched setsched };
# IPC within the domain
allow skype_t self:fifo_file manage_fifo_file_perms;
allow skype_t self:udp_socket create_socket_perms;
allow skype_t self:tcp_socket { accept listen };
# Allow manage rights on ~/.Skype
manage_dirs_pattern(skype_t, skype_home_t, skype_home_t)
manage_files_pattern(skype_t, skype_home_t, skype_home_t)
userdom_user_home_dir_filetrans(skype_t, skype_home_t, dir, ".Skype")
# Shared memory (also needed for X11)
manage_files_pattern(skype_t, skype_tmpfs_t, skype_tmpfs_t)
manage_lnk_files_pattern(skype_t, skype_tmpfs_t, skype_tmpfs_t)
manage_fifo_files_pattern(skype_t, skype_tmpfs_t, skype_tmpfs_t)
manage_sock_files_pattern(skype_t, skype_tmpfs_t, skype_tmpfs_t)
fs_tmpfs_filetrans(skype_t, skype_tmpfs_t, { file lnk_file fifo_file sock_file })
# Temporary (user) files
manage_files_pattern(skype_t, skype_tmp_t, skype_tmp_t)
manage_sock_files_pattern(skype_t, skype_tmp_t, skype_tmp_t)
files_tmp_filetrans(skype_t, skype_tmp_t, { file sock_file })
# Application is an X11 application
xserver_user_x_domain_template(skype, skype_t, skype_tmpfs_t)
# Network access
corenet_tcp_bind_generic_node(skype_t)
corenet_udp_bind_generic_node(skype_t)
# Connect to central authentication service
corenet_tcp_connect_http_port(skype_t)
corenet_tcp_connect_all_unreserved_ports(skype_t)
# Listen for incoming traffic
corenet_tcp_bind_all_unreserved_ports(skype_t)
corenet_udp_bind_all_unreserved_ports(skype_t)
# Trivial
auth_use_nsswitch(skype_t)
miscfiles_read_fonts(skype_t)
miscfiles_read_localization(skype_t)
miscfiles_read_generic_certs(skype_t)
# Terminal (tty) output
userdom_use_user_terminals(skype_t)
# Lots of denials, not sure if needed
fs_getattr_xattr_fs(skype_t)
fs_getattr_tmpfs(skype_t)
# Network info
kernel_read_network_state(skype_t)
# Voice and video calls
tunable_policy(`skype_use_audio',`
dev_read_sound(skype_t)
dev_write_sound(skype_t)
')
tunable_policy(`skype_use_video',`
dev_read_video_dev(skype_t)
dev_write_video_dev(skype_t)
')
# Manage user content
tunable_policy(`skype_manage_user_content',`
userdom_manage_user_home_content_dirs(skype_t)
userdom_manage_user_home_content_files(skype_t)
',`
userdom_dontaudit_manage_user_home_content_dirs(skype_t)
userdom_dontaudit_read_user_home_content_files(skype_t)
')
# D-Bus interaction
optional_policy(`
dbus_system_bus_client(skype_t)
dbus_all_session_bus_client(skype_t)
')
# ALSA support
optional_policy(`
alsa_domain(skype_t, skype_tmpfs_t)
')
# Pulseaudio support
optional_policy(`
pulseaudio_manage_home(skype_t)
')
ifdef(`distro_gentoo',`
# User configuration
xdg_manage_downloads_home(skype_t)
')
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment