From 130112f793bd03ae70f02652a3110abcb6ec6f01 Mon Sep 17 00:00:00 2001 From: Mike Makonnen Date: Wed, 20 Aug 2003 06:15:18 +0000 Subject: Add a general mechanism for creating and applying devfs(8) rules in rc(8). It is most useful for applying rules to devfs(5) mount points in /dev or inside jails. The following line of script is sufficient to mount a relatively useful+secure devfs(5) in a jail: devfs_mount_jail /some/jail/dev Some new shell routines available to scripts that source rc.subr(5): o devfs_link - Makes it a little easier to create symlinks o devfs_init_rulesets - Create devfs(8) rulesets from devfs.rules o devfs_set_ruleset - Set a ruleset to a devfs(5) mount o devfs_apply_ruleset - Apply a ruleset to a devfs(5) mount o devfs_domount - Mount devfs(5) and apply some ruleset o devfs_mount_jail - Mount devfs(5) and apply a ruleset appropriate to jails. Additional rulesets can be specified in /etc/devfs.rules. If the devfs_system_ruleset variable is defined in rc.conf and it contains the name of a ruleset defined in /etc/defaults/devfs.rules or user supplied rulesets in /etc/devfs.rules then that ruleset will be applied to /dev at startup by the /etc/rc.d/devfs script. It can also be applied post-startup: /etc/rc.d/devfs start This is a more flexible mechanism than the previous method of using /etc/devfs.conf. However, that method is still available. Note: since devfs(8) doesn't provide any way for creating symlinks as part of a ruleset, anyone wishing to create symlinks in a devfs(5) as part of the bootup sequence will still have to rely on /etc/devfs.conf. --- etc/defaults/Makefile | 2 +- etc/defaults/devfs.rules | 64 ++++++++++++++ etc/defaults/rc.conf | 4 + etc/rc.d/devfs | 12 ++- etc/rc.subr | 218 +++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 298 insertions(+), 2 deletions(-) create mode 100644 etc/defaults/devfs.rules (limited to 'etc') diff --git a/etc/defaults/Makefile b/etc/defaults/Makefile index 3e9a52d2c9be..56e74ffd4be7 100644 --- a/etc/defaults/Makefile +++ b/etc/defaults/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -FILES= pccard.conf periodic.conf rc.conf +FILES= devfs.rules pccard.conf periodic.conf rc.conf NOOBJ= noobj FILESDIR= /etc/defaults FILESMODE= 644 diff --git a/etc/defaults/devfs.rules b/etc/defaults/devfs.rules new file mode 100644 index 000000000000..aa618997ce01 --- /dev/null +++ b/etc/defaults/devfs.rules @@ -0,0 +1,64 @@ +# +# The following are some default rules for devfs(5) mounts. +# The format is very simple. Empty lines and lines begining +# with a hash '#' are ignored. If the hash mark occurs anywhere +# other than the beginning of a line, it and any subsequent +# characters will be ignored. A line in between brackets '[]' +# denotes the beginning of a ruleset. In the brackets should +# be a name for the rule and its ruleset number. Any other lines +# will be considered to be the 'action' part of a rule +# passed to the devfs(8) command. These will be passed +# "as-is" to the devfs(8) command with the exception that +# any references to other rulesets will be expanded first. These +# references must include a dollar sign '$' in-front of the +# name to be expanded properly. +# +# $FreeBSD$ +# + +# Very basic and secure ruleset: Hide everything. +# Used as a basis for other rules. +# +[devfsrules_hide_all=1] +add hide + +# Basic devices typically necessary. +# Requires: devfsrules_hide_all +# +[devfsrules_unhide_basic=2] +add path null unhide +add path zero unhide +add path random unhide +add path urandom unhide + +# Devices typically needed to support logged-in users. +# Requires: devfsrules_hide_all +# +[devfsrules_unhide_login=3] +add path 'ptyp*' unhide +add path 'ptyq*' unhide +add path 'ptyr*' unhide +add path 'ptys*' unhide +add path 'ptyP*' unhide +add path 'ptyQ*' unhide +add path 'ptyR*' unhide +add path 'ptyS*' unhide +add path 'ttyp*' unhide +add path 'ttyq*' unhide +add path 'ttyr*' unhide +add path 'ttys*' unhide +add path 'ttyP*' unhide +add path 'ttyQ*' unhide +add path 'ttyR*' unhide +add path 'ttyS*' unhide +add path 'fd/*' unhide +add path stdin unhide +add path stdout unhide +add path stderr unhide + +# Devices usually found in a jail. +# +[devfsrules_jail=4] +add include $devfsrules_hide_all +add include $devfsrules_unhide_basic +add include $devfsrules_unhide_login diff --git a/etc/defaults/rc.conf b/etc/defaults/rc.conf index b247b3256c1b..be380f2973b7 100644 --- a/etc/defaults/rc.conf +++ b/etc/defaults/rc.conf @@ -434,6 +434,10 @@ jail_set_hostname_allow="YES" # Allow root user in a jail to change its hostname jail_socket_unixiproute_only="YES" # Route only TCP/IP within a jail jail_sysvipc_allow="NO" # Allow SystemV IPC use from within a jail watchdogd_enable="NO" # Start the software watchdog daemon +devfs_rulesets="/etc/defaults/devfs.rules /etc/devfs.rules" # Files containing + # devfs(8) rules. +devfs_system_ruleset="" # The name of a ruleset to apply to /dev + ############################################################## ### Define source_rc_confs, the mechanism used by /etc/rc.* ## diff --git a/etc/rc.d/devfs b/etc/rc.d/devfs index aaf828b51c12..07934fb4dc79 100644 --- a/etc/rc.d/devfs +++ b/etc/rc.d/devfs @@ -11,9 +11,19 @@ . /etc/rc.subr name="devfs" -start_cmd='read_devfs_conf' +start_cmd='devfs_start' stop_cmd=':' +devfs_start() +{ + if [ -n "$devfs_system_ruleset" ]; then + devfs_init_rulesets + devfs_set_ruleset $devfs_system_ruleset /dev + devfs_apply_ruleset $devfs_system_ruleset /dev + fi + read_devfs_conf +} + read_devfs_conf() { if [ -r /etc/devfs.conf ]; then diff --git a/etc/rc.subr b/etc/rc.subr index 87f9c4f8fcf5..c45938c71a92 100644 --- a/etc/rc.subr +++ b/etc/rc.subr @@ -1033,3 +1033,221 @@ backup_file() esac fi } + +# devfs_link dir src link +# Make a symbolic link 'link' to src in chroot/dev. +# Returns 0 on sucess. +# +devfs_link() +{ + local dir src link _me + dir="$1" + src="$2" + link="$3" + _me="devfs_link" + + if [ -z "$dir" -o -z "$src" -o -z "$link" ]; then + warn "devfs_link(): requires three arguments." + return 1 + fi + if [ -z "$dir" ]; then + warn "$_me: the directory ($dir) does not exist" + return 1 + fi + cd ${chroot}/dev + if ! ln -sf $src $link ; then + warn "$_me: unable to link $link --> $src in $dir" + return 1 + fi + return 0 +} + +# devfs_rulesets_from_file file +# Reads a set of devfs commands from file, and creates +# the specified rulesets with their rules. Returns non-zero +# if there was an error. +# +devfs_rulesets_from_file() +{ + local file _err _me + file="$1" + _me="devfs_rulesets_from_file" + _err=0 + + if [ -z "$file" ]; then + warn "$_me: you must specify a file" + return 1 + fi + if [ ! -e "$file" ]; then + debug "$_me: no such file ($file)" + return 0 + fi + debug "reading rulesets from file ($file)" + { while read line + do + case $line in + \#*) + continue + ;; + \[*\]*) + rulenum=`expr "$line" : "\[.*=\([0-9]*\)\]"` + if [ -z "$rulenum" ]; then + warn "$_me: cannot extract rule number ($line)" + _err=1 + break + fi + rulename=`expr "$line" : "\[\(.*\)=[0-9]*\]"` + if [ -z "$rulename" ]; then + warn "$_me: cannot extract rule name ($line)" + _err=1 + break; + fi + eval $rulename=\$rulenum + debug "found ruleset: $rulename=$rulenum" + if ! /sbin/devfs rule -s $rulenum delset ; then + _err=1 + break + fi + ;; + *) + rulecmd="${line%%"\#*"}" + # evaluate the command incase it includes + # other rules + if [ -n "$rulecmd" ]; then + debug "adding rule ($rulecmd)" + if ! eval /sbin/devfs rule -s $rulenum $rulecmd + then + _err=1 + break + fi + fi + ;; + esac + if [ $_err -ne 0 ]; then + debug "error in $_me" + break + fi + done } < $file + return $_err +} + +# devfs_init_rulesets +# Initializes rulesets from configuration files. Returns +# non-zero if there was an error. +# +devfs_init_rulesets() +{ + local file _me + _me="devfs_init_rulesets" + + # Go through this only once + if [ -n "$devfs_rulesets_init" ]; then + debug "$_me: devfs rulesets already initialized" + return + fi + for file in $devfs_rulesets ; do + devfs_rulesets_from_file $file || return 1 + done + devfs_rulesets_init=1 + debug "$_me: devfs rulesets initialized" + return 0 +} + +# devfs_set_ruleset ruleset [dir] +# Sets the default ruleset of dir to ruleset. The ruleset arguement +# must be a ruleset name as specified in devfs.rules(5) file. +# Returns non-zero if it could not set it successfully. +# +devfs_set_ruleset() +{ + local devdir rs _me + [ -n "$1" ] && eval rs=\$$1 || rs= + [ -n "$2" ] && devdir="-m "$2"" || devdir= + _me="devfs_set_ruleset" + + if [ -z "$rs" ]; then + warn "$_me: you must specify a ruleset number" + return 1 + fi + debug "$_me: setting ruleset ($rs) on mount-point (${devdir#-m })" + if ! /sbin/devfs $devdir ruleset $rs ; then + warn "$_me: unable to set ruleset $rs to ${devdir#-m }" + return 1 + fi + return 0 +} + +# devfs_apply_ruleset ruleset [dir] +# Apply ruleset number $ruleset to the devfs mountpoint $dir. +# The ruleset argument must be a ruleset name as specified +# in a devfs.rules(5) file. Returns 0 on success or non-zero +# if it could not apply the ruleset. +# +devfs_apply_ruleset() +{ + local devdir rs _me + [ -n "$1" ] && eval rs=\$$1 || rs= + [ -n "$2" ] && devdir="-m "$2"" || devdir= + _me="devfs_apply_ruleset" + + if [ -z "$rs" ]; then + warn "$_me: you must specify a ruleset" + return 1 + fi + debug "$_me: applying ruleset ($rs) to mount-point (${devdir#-m })" + if ! /sbin/devfs $devdir rule -s $rs applyset ; then + warn "$_me: unable to apply ruleset $rs to ${devdir#-m }" + return 1 + fi + return 0 +} + +# devfs_domount dir [ruleset] +# Mount devfs on dir. If ruleset is specified it is set +# on the mount-point. It must also be a ruleset name as specified +# in a devfs.rules(5) file. Returns 0 on success. +# +devfs_domount() +{ + local devdir rs _me + devdir="$1" + [ -n "$2" ] && rs=$2 || rs= + _me="devfs_domount()" + + if [ -z "$devdir" ]; then + warn "$_me: you must specify a mount-point" + return 1 + fi + debug "$_me: mount-point is ($devdir), ruleset is ($rs)" + if ! mount -t devfs dev "$devdir" ; then + warn "$_me: Unable to mount devfs on $devdir" + return 1 + fi + if [ -n "$rs" ]; then + devfs_init_rulesets + devfs_set_ruleset $rs $devdir + fi + return 0 +} + +# devfs_mount_jail dir [ruleset] +# Mounts a devfs file system appropriate for jails +# on the directory dir. If ruleset is specified, the ruleset +# it names will be used instead. If present, ruleset must +# be the name of a ruleset as defined in a devfs.rules(5) file. +# This function returns non-zero if an error occurs. +# +devfs_mount_jail() +{ + local jdev rs _me + jdev="$1" + [ -n "$2" ] && rs=$2 || rs="devfsrules_jail" + _me="devfs_mount_jail" + + devfs_init_rulesets + if ! devfs_domount "$jdev" $rs ; then + warn "$_me: devfs was not mounted on $jdev" + return 1 + fi + return 0 +} -- cgit v1.2.3