libselinux/libselinux-fedora.patch
Petr Lautrbach e58e944835 libselinux-2.5-0.1.rc1
Update to upstream rc1 release 2016-01-07
2016-02-21 14:35:44 +01:00

2092 lines
55 KiB
Diff

diff --git libselinux-2.5-rc1/ChangeLog libselinux-2.5-rc1/ChangeLog
index 993158f..2994ded 100644
--- libselinux-2.5-rc1/ChangeLog
+++ libselinux-2.5-rc1/ChangeLog
@@ -1,4 +1,6 @@
2.5-rc1 2016-01-07
+ * Add selinux_restorecon function, from Richard Haines.
+ * read_spec_entry: fail on non-ascii, from William Roberts.
* Add man information about thread specific functions, from Dan Waslh.
* Don't wrap rpm_execcon with DISABLE_RPM with SWIG, from Petr Lautrbach.
* Correct line count for property and service context files, from Richard Haines.
diff --git libselinux-2.5-rc1/Makefile libselinux-2.5-rc1/Makefile
index 6142b60..bdf9de8 100644
--- libselinux-2.5-rc1/Makefile
+++ libselinux-2.5-rc1/Makefile
@@ -1,4 +1,4 @@
-SUBDIRS = src include utils man
+SUBDIRS = src include utils man golang
DISABLE_AVC ?= n
DISABLE_SETRANS ?= n
diff --git libselinux-2.5-rc1/golang/Makefile libselinux-2.5-rc1/golang/Makefile
new file mode 100644
index 0000000..b75677b
--- /dev/null
+++ libselinux-2.5-rc1/golang/Makefile
@@ -0,0 +1,22 @@
+# Installation directories.
+PREFIX ?= $(DESTDIR)/usr
+LIBDIR ?= $(DESTDIR)/usr/lib
+GODIR ?= $(LIBDIR)/golang/src/pkg/github.com/selinux
+all:
+
+install:
+ [ -d $(GODIR) ] || mkdir -p $(GODIR)
+ install -m 644 selinux.go $(GODIR)
+
+test:
+ @mkdir selinux
+ @cp selinux.go selinux
+ GOPATH=$(pwd) go run test.go
+ @rm -rf selinux
+
+clean:
+ @rm -f *~
+ @rm -rf selinux
+indent:
+
+relabel:
diff --git libselinux-2.5-rc1/golang/selinux.go libselinux-2.5-rc1/golang/selinux.go
new file mode 100644
index 0000000..34bf6bb
--- /dev/null
+++ libselinux-2.5-rc1/golang/selinux.go
@@ -0,0 +1,412 @@
+package selinux
+
+/*
+ The selinux package is a go bindings to libselinux required to add selinux
+ support to docker.
+
+ Author Dan Walsh <dwalsh@redhat.com>
+
+ Used some ideas/code from the go-ini packages https://github.com/vaughan0
+ By Vaughan Newton
+*/
+
+// #cgo pkg-config: libselinux
+// #include <selinux/selinux.h>
+// #include <stdlib.h>
+import "C"
+import (
+ "bufio"
+ "crypto/rand"
+ "encoding/binary"
+ "fmt"
+ "io"
+ "os"
+ "path"
+ "path/filepath"
+ "regexp"
+ "strings"
+ "unsafe"
+)
+
+var (
+ assignRegex = regexp.MustCompile(`^([^=]+)=(.*)$`)
+ mcsList = make(map[string]bool)
+)
+
+func Matchpathcon(path string, mode os.FileMode) (string, error) {
+ var con C.security_context_t
+ var scon string
+ rc, err := C.matchpathcon(C.CString(path), C.mode_t(mode), &con)
+ if rc == 0 {
+ scon = C.GoString(con)
+ C.free(unsafe.Pointer(con))
+ }
+ return scon, err
+}
+
+func Setfilecon(path, scon string) (int, error) {
+ rc, err := C.lsetfilecon(C.CString(path), C.CString(scon))
+ return int(rc), err
+}
+
+func Getfilecon(path string) (string, error) {
+ var scon C.security_context_t
+ var fcon string
+ rc, err := C.lgetfilecon(C.CString(path), &scon)
+ if rc >= 0 {
+ fcon = C.GoString(scon)
+ err = nil
+ }
+ return fcon, err
+}
+
+func Setfscreatecon(scon string) (int, error) {
+ var (
+ rc C.int
+ err error
+ )
+ if scon != "" {
+ rc, err = C.setfscreatecon(C.CString(scon))
+ } else {
+ rc, err = C.setfscreatecon(nil)
+ }
+ return int(rc), err
+}
+
+func Getfscreatecon() (string, error) {
+ var scon C.security_context_t
+ var fcon string
+ rc, err := C.getfscreatecon(&scon)
+ if rc >= 0 {
+ fcon = C.GoString(scon)
+ err = nil
+ C.freecon(scon)
+ }
+ return fcon, err
+}
+
+func Getcon() string {
+ var pcon C.security_context_t
+ C.getcon(&pcon)
+ scon := C.GoString(pcon)
+ C.freecon(pcon)
+ return scon
+}
+
+func Getpidcon(pid int) (string, error) {
+ var pcon C.security_context_t
+ var scon string
+ rc, err := C.getpidcon(C.pid_t(pid), &pcon)
+ if rc >= 0 {
+ scon = C.GoString(pcon)
+ C.freecon(pcon)
+ err = nil
+ }
+ return scon, err
+}
+
+func Getpeercon(socket int) (string, error) {
+ var pcon C.security_context_t
+ var scon string
+ rc, err := C.getpeercon(C.int(socket), &pcon)
+ if rc >= 0 {
+ scon = C.GoString(pcon)
+ C.freecon(pcon)
+ err = nil
+ }
+ return scon, err
+}
+
+func Setexeccon(scon string) error {
+ var val *C.char
+ if !SelinuxEnabled() {
+ return nil
+ }
+ if scon != "" {
+ val = C.CString(scon)
+ } else {
+ val = nil
+ }
+ _, err := C.setexeccon(val)
+ return err
+}
+
+type Context struct {
+ con []string
+}
+
+func (c *Context) SetUser(user string) {
+ c.con[0] = user
+}
+func (c *Context) GetUser() string {
+ return c.con[0]
+}
+func (c *Context) SetRole(role string) {
+ c.con[1] = role
+}
+func (c *Context) GetRole() string {
+ return c.con[1]
+}
+func (c *Context) SetType(setype string) {
+ c.con[2] = setype
+}
+func (c *Context) GetType() string {
+ return c.con[2]
+}
+func (c *Context) SetLevel(mls string) {
+ c.con[3] = mls
+}
+func (c *Context) GetLevel() string {
+ return c.con[3]
+}
+func (c *Context) Get() string {
+ return strings.Join(c.con, ":")
+}
+func (c *Context) Set(scon string) {
+ c.con = strings.SplitN(scon, ":", 4)
+}
+func NewContext(scon string) Context {
+ var con Context
+ con.Set(scon)
+ return con
+}
+
+func SelinuxEnabled() bool {
+ b := C.is_selinux_enabled()
+ if b > 0 {
+ return true
+ }
+ return false
+}
+
+const (
+ Enforcing = 1
+ Permissive = 0
+ Disabled = -1
+)
+
+func SelinuxGetEnforce() int {
+ return int(C.security_getenforce())
+}
+
+func SelinuxGetEnforceMode() int {
+ var enforce C.int
+ C.selinux_getenforcemode(&enforce)
+ return int(enforce)
+}
+
+func mcsAdd(mcs string) {
+ mcsList[mcs] = true
+}
+
+func mcsDelete(mcs string) {
+ mcsList[mcs] = false
+}
+
+func mcsExists(mcs string) bool {
+ return mcsList[mcs]
+}
+
+func IntToMcs(id int, catRange uint32) string {
+ if (id < 1) || (id > 523776) {
+ return ""
+ }
+
+ SETSIZE := int(catRange)
+ TIER := SETSIZE
+
+ ORD := id
+ for ORD > TIER {
+ ORD = ORD - TIER
+ TIER -= 1
+ }
+ TIER = SETSIZE - TIER
+ ORD = ORD + TIER
+ return fmt.Sprintf("s0:c%d,c%d", TIER, ORD)
+}
+
+func uniqMcs(catRange uint32) string {
+ var n uint32
+ var c1, c2 uint32
+ var mcs string
+ for {
+ binary.Read(rand.Reader, binary.LittleEndian, &n)
+ c1 = n % catRange
+ binary.Read(rand.Reader, binary.LittleEndian, &n)
+ c2 = n % catRange
+ if c1 == c2 {
+ continue
+ } else {
+ if c1 > c2 {
+ t := c1
+ c1 = c2
+ c2 = t
+ }
+ }
+ mcs = fmt.Sprintf("s0:c%d,c%d", c1, c2)
+ if mcsExists(mcs) {
+ continue
+ }
+ mcsAdd(mcs)
+ break
+ }
+ return mcs
+}
+func freeContext(processLabel string) {
+ var scon Context
+ scon = NewContext(processLabel)
+ mcsDelete(scon.GetLevel())
+}
+
+func GetLxcContexts() (processLabel string, fileLabel string) {
+ var val, key string
+ var bufin *bufio.Reader
+ if !SelinuxEnabled() {
+ return
+ }
+ lxcPath := C.GoString(C.selinux_lxc_contexts_path())
+ fileLabel = "system_u:object_r:svirt_sandbox_file_t:s0"
+ processLabel = "system_u:system_r:svirt_lxc_net_t:s0"
+
+ in, err := os.Open(lxcPath)
+ if err != nil {
+ goto exit
+ }
+
+ defer in.Close()
+ bufin = bufio.NewReader(in)
+
+ for done := false; !done; {
+ var line string
+ if line, err = bufin.ReadString('\n'); err != nil {
+ if err == io.EOF {
+ done = true
+ } else {
+ goto exit
+ }
+ }
+ line = strings.TrimSpace(line)
+ if len(line) == 0 {
+ // Skip blank lines
+ continue
+ }
+ if line[0] == ';' || line[0] == '#' {
+ // Skip comments
+ continue
+ }
+ if groups := assignRegex.FindStringSubmatch(line); groups != nil {
+ key, val = strings.TrimSpace(groups[1]), strings.TrimSpace(groups[2])
+ if key == "process" {
+ processLabel = strings.Trim(val, "\"")
+ }
+ if key == "file" {
+ fileLabel = strings.Trim(val, "\"")
+ }
+ }
+ }
+exit:
+ var scon Context
+ mcs := IntToMcs(os.Getpid(), 1024)
+ scon = NewContext(processLabel)
+ scon.SetLevel(mcs)
+ processLabel = scon.Get()
+ scon = NewContext(fileLabel)
+ scon.SetLevel(mcs)
+ fileLabel = scon.Get()
+ return processLabel, fileLabel
+}
+
+func CopyLevel(src, dest string) (string, error) {
+ if !SelinuxEnabled() {
+ return "", nil
+ }
+ if src == "" {
+ return "", nil
+ }
+ rc, err := C.security_check_context(C.CString(src))
+ if rc != 0 {
+ return "", err
+ }
+ rc, err = C.security_check_context(C.CString(dest))
+ if rc != 0 {
+ return "", err
+ }
+ scon := NewContext(src)
+ tcon := NewContext(dest)
+ tcon.SetLevel(scon.GetLevel())
+ return tcon.Get(), nil
+}
+
+func RestoreCon(fpath string, recurse bool) error {
+ var flabel string
+ var err error
+ var fs os.FileInfo
+
+ if !SelinuxEnabled() {
+ return nil
+ }
+
+ if recurse {
+ var paths []string
+ var err error
+
+ if paths, err = filepath.Glob(path.Join(fpath, "**", "*")); err != nil {
+ return fmt.Errorf("Unable to find directory %v: %v", fpath, err)
+ }
+
+ for _, fpath := range paths {
+ if err = RestoreCon(fpath, false); err != nil {
+ return fmt.Errorf("Unable to restore selinux context for %v: %v", fpath, err)
+ }
+ }
+ return nil
+ }
+ if fs, err = os.Stat(fpath); err != nil {
+ return fmt.Errorf("Unable stat %v: %v", fpath, err)
+ }
+
+ if flabel, err = Matchpathcon(fpath, fs.Mode()); flabel == "" {
+ return fmt.Errorf("Unable to get context for %v: %v", fpath, err)
+ }
+
+ if rc, err := Setfilecon(fpath, flabel); rc != 0 {
+ return fmt.Errorf("Unable to set selinux context for %v: %v", fpath, err)
+ }
+
+ return nil
+}
+
+func Test() {
+ var plabel, flabel string
+ if !SelinuxEnabled() {
+ return
+ }
+
+ plabel, flabel = GetLxcContexts()
+ fmt.Println(plabel)
+ fmt.Println(flabel)
+ freeContext(plabel)
+ plabel, flabel = GetLxcContexts()
+ fmt.Println(plabel)
+ fmt.Println(flabel)
+ freeContext(plabel)
+ if SelinuxEnabled() {
+ fmt.Println("Enabled")
+ } else {
+ fmt.Println("Disabled")
+ }
+ fmt.Println("getenforce ", SelinuxGetEnforce())
+ fmt.Println("getenforcemode ", SelinuxGetEnforceMode())
+ flabel, _ = Matchpathcon("/home/dwalsh/.emacs", 0)
+ fmt.Println(flabel)
+ pid := os.Getpid()
+ fmt.Printf("PID:%d MCS:%s\n", pid, IntToMcs(pid, 1023))
+ fmt.Println(Getcon())
+ fmt.Println(Getfilecon("/etc/passwd"))
+ fmt.Println(Getpidcon(1))
+ Setfscreatecon("unconfined_u:unconfined_r:unconfined_t:s0")
+ fmt.Println(Getfscreatecon())
+ Setfscreatecon("")
+ fmt.Println(Getfscreatecon())
+ fmt.Println(Getpidcon(1))
+}
diff --git libselinux-2.5-rc1/golang/test.go libselinux-2.5-rc1/golang/test.go
new file mode 100644
index 0000000..fed6de8
--- /dev/null
+++ libselinux-2.5-rc1/golang/test.go
@@ -0,0 +1,9 @@
+package main
+
+import (
+ "./selinux"
+)
+
+func main() {
+ selinux.Test()
+}
diff --git libselinux-2.5-rc1/include/selinux/restorecon.h libselinux-2.5-rc1/include/selinux/restorecon.h
new file mode 100644
index 0000000..ba1232e
--- /dev/null
+++ libselinux-2.5-rc1/include/selinux/restorecon.h
@@ -0,0 +1,79 @@
+#ifndef _RESTORECON_H_
+#define _RESTORECON_H_
+
+#include <sys/types.h>
+#include <stdarg.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * selinux_restorecon - Relabel files.
+ * @pathname: specifies file/directory to relabel.
+ * @restorecon_flags: specifies the actions to be performed when relabeling.
+ *
+ * selinux_restorecon(3) will automatically call
+ * selinux_restorecon_default_handle(3) and selinux_restorecon_set_sehandle(3)
+ * first time through to set the selabel_open(3) parameters to use the
+ * currently loaded policy file_contexts and request their computed digest.
+ *
+ * Should other selabel_open(3) parameters be required see
+ * selinux_restorecon_set_sehandle(3).
+ */
+extern int selinux_restorecon(const char *pathname,
+ unsigned int restorecon_flags);
+/*
+ * restorecon_flags options
+ */
+/* Force the checking of labels even if the stored SHA1
+ * digest matches the specfiles SHA1 digest. */
+#define SELINUX_RESTORECON_IGNORE_DIGEST 1
+/* Do not change file labels */
+#define SELINUX_RESTORECON_NOCHANGE 2
+/* If set set change file label to that in spec file.
+ * If not only change type component to that in spec file. */
+#define SELINUX_RESTORECON_SET_SPECFILE_CTX 4
+/* Recursively descend directories */
+#define SELINUX_RESTORECON_RECURSE 8
+/* Log changes to selinux log. Note that if VERBOSE and
+ * PROGRESS are set, then PROGRESS will take precedence. */
+#define SELINUX_RESTORECON_VERBOSE 16
+/* Show progress by printing * to stdout every 1000 files */
+#define SELINUX_RESTORECON_PROGRESS 32
+/* Convert passed-in pathname to canonical pathname */
+#define SELINUX_RESTORECON_REALPATH 64
+/* Prevent descending into directories that have a different
+ * device number than the pathname from which the descent began */
+#define SELINUX_RESTORECON_XDEV 128
+
+/**
+ * selinux_restorecon_set_sehandle - Set the global fc handle.
+ * @handle: specifies handle to set as the global fc handle.
+ *
+ * Called by a process that has already called selabel_open(3) with it's
+ * required parameters, or if selinux_restorecon_default_handle(3) has been
+ * called to set the default selabel_open(3) parameters.
+ */
+extern void selinux_restorecon_set_sehandle(struct selabel_handle *hndl);
+
+/**
+ * selinux_restorecon_default_handle - Sets default selabel_open(3) parameters
+ * to use the currently loaded policy and
+ * file_contexts, also requests the digest.
+ */
+extern struct selabel_handle *selinux_restorecon_default_handle(void);
+
+/**
+ * selinux_restorecon_set_exclude_list - Add a list of files or
+ * directories that are to be excluded
+ * from relabeling.
+ * @exclude_list: containing a NULL terminated list of one or more
+ * directories or files not to be relabeled.
+ */
+extern void selinux_restorecon_set_exclude_list(const char **exclude_list);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git libselinux-2.5-rc1/man/man3/selinux_restorecon.3 libselinux-2.5-rc1/man/man3/selinux_restorecon.3
new file mode 100644
index 0000000..152b29c
--- /dev/null
+++ libselinux-2.5-rc1/man/man3/selinux_restorecon.3
@@ -0,0 +1,195 @@
+.TH "selinux_restorecon" "3" "20 Oct 2015" "Security Enhanced Linux" "SELinux API documentation"
+
+.SH "NAME"
+selinux_restorecon \- restore file(s) default SELinux security contexts
+.
+.SH "SYNOPSIS"
+.B #include <selinux/restorecon.h>
+.sp
+.BI "int selinux_restorecon(const char **" pathname ,
+.in +\w'int selinux_restorecon('u
+.br
+.BI "unsigned int " restorecon_flags ");"
+.in
+.
+.SH "DESCRIPTION"
+.BR selinux_restorecon ()
+restores file default security contexts based on:
+.sp
+.RS
+.IR pathname
+containing a directory or file to be relabeled.
+.br
+If this is a directory and the
+.IR restorecon_flags
+.B SELINUX_RESTORECON_RECURSE
+has been set (for decending through directories), then
+.BR selinux_restorecon ()
+will write an SHA1 digest of the combined specfiles (see the
+.B NOTES
+section for details) to an extended attribute of
+.IR security.restorecon_last
+once the relabeling has been completed successfully. This digest will be
+checked should
+.BR selinux_restorecon ()
+be rerun
+with the
+.IR restorecon_flags
+.B SELINUX_RESTORECON_RECURSE
+flag set. If any of the specfiles had been updated, the digest
+will also be updated. However if the digest is the same, no relabeling checks
+will take place (unless the
+.B SELINUX_RESTORECON_IGNORE_DIGEST
+is set).
+.sp
+.IR restorecon_flags
+contains the labeling option/rules as follows:
+.sp
+.RS
+.sp
+.B SELINUX_RESTORECON_IGNORE_DIGEST
+force the checking of labels even if the stored SHA1 digest matches the
+specfiles SHA1 digest. The specfiles digest will be written to the
+.IR security.restorecon_last
+extended attribute once relabeling has been completed successfully provided the
+.B SELINUX_RESTORECON_NOCHANGE
+has not been set.
+.sp
+.B SELINUX_RESTORECON_NOCHANGE
+don't change any file labels (passive check) or update the digest in the
+.IR security.restorecon_last
+extended attribute.
+.sp
+.B SELINUX_RESTORECON_SET_SPECFILE_CTX
+If set, reset the files label to match the default specfile context.
+if not set only reset the files "type" component of the context to match the
+default specfile context.
+.br
+
+.sp
+.B SELINUX_RESTORECON_RECURSE
+change file and directory labels recursively (descend directories)
+and if successful write an SHA1 digest of the combined specfiles to an
+extended attribute as described in the
+.B NOTES
+section.
+.sp
+.B SELINUX_RESTORECON_VERBOSE
+log file label changes.
+.RS
+Note that if
+.B SELINUX_RESTORECON_VERBOSE
+and
+.B SELINUX_RESTORECON_PROGRESS
+are set, then
+.B SELINUX_RESTORECON_PROGRESS
+will take precedence.
+.RE
+.sp
+.B SELINUX_RESTORECON_PROGRESS
+show progress by printing * to stdout every 1000 files.
+.sp
+.B SELINUX_RESTORECON_REALPATH
+convert passed-in
+.I pathname
+to the canonical pathname using
+.BR realpath (3).
+.sp
+.B SELINUX_RESTORECON_XDEV
+prevent descending into directories that have a different device number than
+the
+.I pathname
+entry from which the descent began.
+.RE
+.sp
+The behavior regarding the checking and updating of the SHA1 digest described
+above is the default behavior. It is possible to change this by first calling
+.BR selabel_open (3)
+and not enabling the
+.B SELABEL_OPT_DIGEST
+option, then calling
+.BR selinux_restorecon_set_sehandle (3)
+to set the handle to be used by
+.BR selinux_restorecon (3).
+.sp
+If the
+.I pathname
+is a directory path, then it is possible to set files/directories to be exluded
+from the path by calling
+.BR selinux_restorecon_set_exclude_list (3)
+with a
+.B NULL
+terminated list before calling
+.BR selinux_restorecon (3).
+.RE
+.
+.SH "RETURN VALUE"
+On success, zero is returned. On error, \-1 is returned and
+.I errno
+is set appropriately.
+.
+.SH "NOTES"
+To improve performance when relabeling file systems recursively (e.g. the
+.IR restorecon_flags
+.B SELINUX_RESTORECON_RECURSE
+flag is set)
+.BR selinux_restorecon ()
+will write an SHA1 digest of the specfiles that are processed by
+.BR selabel_open (3)
+to an extended attribute named
+.IR security.restorecon_last
+to the directory specified in the
+.IR pathname .
+.sp
+To check the extended attribute entry use
+.BR getfattr (1) ,
+for example:
+.sp
+.RS
+getfattr -e hex -n security.restorecon_last /
+.RE
+.sp
+The SHA1 digest is calculated by
+.BR selabel_open (3)
+concatenating the specfiles it reads during initialisation with the
+resulting digest and list of specfiles being retrieved by
+.BR selabel_digest (3).
+.sp
+The specfiles consist of the mandatory
+.I file_contexts
+file plus any subs, subs_dist, local and homedir entries (text or binary versions)
+as determined by any
+.BR selabel_open (3)
+options e.g.
+.BR SELABEL_OPT_BASEONLY .
+.sp
+Should any of the specfiles have changed, then when
+.BR selinux_restorecon ()
+is run again with the
+.B SELINUX_RESTORECON_RECURSE
+flag set, a new SHA1 digest will be calculated and all files will be automatically
+relabeled depending on the settings of the
+.B SELINUX_RESTORECON_SET_SPECFILE_CTX
+flag (provided
+.B SELINUX_RESTORECON_NOCHANGE
+is not set).
+.sp
+.B /sys
+and in-memory filesystems do not support the
+.IR security.restorecon_last
+extended attribute.
+.sp
+.BR selinux_restorecon ()
+does not check whether the mounted filesystems support the
+.B seclabel
+option. These should be set by the caller by
+.BR selinux_restorecon_set_exclude_list (3)
+in the
+.IR exclude_list .
+.
+.SH "SEE ALSO"
+.BR selinux_restorecon_set_sehandle (3),
+.br
+.BR selinux_restorecon_default_handle (3),
+.br
+.BR selinux_restorecon_set_exclude_list (3),
diff --git libselinux-2.5-rc1/man/man3/selinux_restorecon_default_handle.3 libselinux-2.5-rc1/man/man3/selinux_restorecon_default_handle.3
new file mode 100644
index 0000000..0f1e737
--- /dev/null
+++ libselinux-2.5-rc1/man/man3/selinux_restorecon_default_handle.3
@@ -0,0 +1,59 @@
+.TH "selinux_restorecon_default_handle" "3" "20 Oct 2015" "Security Enhanced Linux" "SELinux API documentation"
+
+.SH "NAME"
+selinux_restorecon_default_handle \- sets default parameters for
+.BR selinux_restorecon (3)
+.
+.SH "SYNOPSIS"
+.B #include <selinux/restorecon.h>
+.br
+.B #include <selinux/label.h>
+.sp
+.B "struct selabel_handle *selinux_restorecon_default_handle(void);"
+.
+.SH "DESCRIPTION"
+.BR selinux_restorecon_default_handle ()
+sets default parameters for
+.BR selinux_restorecon (3)
+by calling
+.BR selabel_open (3)
+with the
+.B SELABEL_OPT_DIGEST
+option only. This will enable a digest to be calculated on the currently
+loaded policy
+.BR file_contexts (5)
+set of files as described in the
+.B NOTES
+section of
+.BR selinux_restorecon (3).
+.sp
+Calling
+.BR selinux_restorecon_default_handle ()
+is optional, however if used then
+.BR selinux_restorecon_set_sehandle (3)
+should be called with the returned handle to set this for use by
+.BR selinux_restorecon (3).
+.sp
+.BR selinux_restorecon_default_handle ()
+is optional as
+.BR selinux_restorecon (3)
+will automatically call this and
+.BR selinux_restorecon_set_sehandle (3)
+provided a handle has not already been set, for
+example by
+.BR selinux_restorecon_set_sehandle (3)
+to set customised
+.BR selabel_open (3)
+parameters.
+.
+.SH "RETURN VALUE"
+A non\-NULL handle value is returned on success. On error, NULL is returned and
+.I errno
+is set appropriately.
+.
+.SH "SEE ALSO"
+.BR selinux_restorecon (3),
+.br
+.BR selinux_restorecon_set_sehandle (3),
+.br
+.BR selinux_restorecon_set_exclude_list (3)
diff --git libselinux-2.5-rc1/man/man3/selinux_restorecon_set_exclude_list.3 libselinux-2.5-rc1/man/man3/selinux_restorecon_set_exclude_list.3
new file mode 100644
index 0000000..ea1fb78
--- /dev/null
+++ libselinux-2.5-rc1/man/man3/selinux_restorecon_set_exclude_list.3
@@ -0,0 +1,32 @@
+.TH "selinux_restorecon_set_exclude_list" "3" "20 Oct 2015" "Security Enhanced Linux" "SELinux API documentation"
+
+.SH "NAME"
+selinux_restorecon_set_exclude_list \- set list of files/directories to be
+excluded from relabeling.
+.
+.SH "SYNOPSIS"
+.B #include <selinux/restorecon.h>
+.sp
+.BI "void selinux_restorecon_set_exclude_list(const char **" exclude_list ");"
+.in +\w'void selinux_restorecon_set_exclude_list('u
+.
+.SH "DESCRIPTION"
+.BR selinux_restorecon_set_exclude_list ()
+passes to
+.BR selinux_restorecon (3)
+a pointer containing a
+.B NULL
+terminated list of one or more directories or files that are not to be
+relabeled in
+.IR exclude_list .
+.sp
+.BR selinux_restorecon_set_exclude_list ()
+must be called prior to
+.BR selinux_restorecon (3).
+.
+.SH "SEE ALSO"
+.BR selinux_restorecon (3),
+.br
+.BR selinux_restorecon_set_sehandle (3),
+.br
+.BR selinux_restorecon_default_handle (3)
diff --git libselinux-2.5-rc1/man/man3/selinux_restorecon_set_sehandle.3 libselinux-2.5-rc1/man/man3/selinux_restorecon_set_sehandle.3
new file mode 100644
index 0000000..6182f54
--- /dev/null
+++ libselinux-2.5-rc1/man/man3/selinux_restorecon_set_sehandle.3
@@ -0,0 +1,39 @@
+.TH "selinux_restorecon_set_sehandle" "3" "20 Oct 2015" "Security Enhanced Linux" "SELinux API documentation"
+
+.SH "NAME"
+selinux_restorecon_set_sehandle \- set a labeling handle for use by
+.BR selinux_restorecon (3)
+.
+.SH "SYNOPSIS"
+.B #include <selinux/restorecon.h>
+.br
+.B #include <selinux/label.h>
+.sp
+.BI "void selinux_restorecon_set_sehandle(struct selabel_handle *" handle ");"
+.in +\w'void selinux_restorecon_set_sehandle('u
+.
+.SH "DESCRIPTION"
+.BR selinux_restorecon_set_sehandle ()
+sets the
+.I handle
+to be use by
+.BR selinux_restorecon (3)
+when relabeling files.
+.sp
+.BR selinux_restorecon_set_sehandle ()
+is generally used when customised
+.BR selabel_open (3)
+parameters are required to perform relabeling operations with
+.BR selinux_restorecon (3).
+.sp
+.BR selinux_restorecon_set_sehandle ()
+will output to the default SELinux log information regarding whether a digest
+is available or not. If it were available, the message will contain the SHA1
+digest and a list of specfiles used to compute the digest.
+.
+.SH "SEE ALSO"
+.BR selinux_restorecon (3),
+.br
+.BR selinux_restorecon_set_exclude_list (3),
+.br
+.BR selinux_restorecon_default_handle (3)
diff --git libselinux-2.5-rc1/man/man8/selinux.8 libselinux-2.5-rc1/man/man8/selinux.8
index 6f1034b..c9f188c 100644
--- libselinux-2.5-rc1/man/man8/selinux.8
+++ libselinux-2.5-rc1/man/man8/selinux.8
@@ -91,11 +91,13 @@ This manual page was written by Dan Walsh <dwalsh@redhat.com>.
.BR sepolicy (8),
.BR system-config-selinux (8),
.BR togglesebool (8),
-.BR restorecon (8),
.BR fixfiles (8),
+.BR restorecon (8),
.BR setfiles (8),
.BR semanage (8),
-.BR sepolicy(8)
+.BR sepolicy(8),
+.BR seinfo(8),
+.BR sesearch(8)
Every confined service on the system has a man page in the following format:
.br
diff --git libselinux-2.5-rc1/src/Makefile libselinux-2.5-rc1/src/Makefile
index 79d50d2..d0021ae 100644
--- libselinux-2.5-rc1/src/Makefile
+++ libselinux-2.5-rc1/src/Makefile
@@ -73,7 +73,7 @@ CFLAGS ?= -O -Wall -W -Wundef -Wformat-y2k -Wformat-security -Winit-self -Wmissi
-fipa-pure-const -Wno-suggest-attribute=pure -Wno-suggest-attribute=const \
-Werror -Wno-aggregate-return -Wno-redundant-decls
-override CFLAGS += -I../include -I$(INCLUDEDIR) -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 $(EMFLAGS)
+override CFLAGS += -I../include -I$(INCLUDEDIR) -D_GNU_SOURCE $(EMFLAGS)
SWIG_CFLAGS += -Wno-error -Wno-unused-variable -Wno-unused-but-set-variable -Wno-unused-parameter \
-Wno-shadow -Wno-uninitialized -Wno-missing-prototypes -Wno-missing-declarations
diff --git libselinux-2.5-rc1/src/avc_sidtab.c libselinux-2.5-rc1/src/avc_sidtab.c
index 9669264..c775430 100644
--- libselinux-2.5-rc1/src/avc_sidtab.c
+++ libselinux-2.5-rc1/src/avc_sidtab.c
@@ -81,6 +81,11 @@ sidtab_context_to_sid(struct sidtab *s,
int hvalue, rc = 0;
struct sidtab_node *cur;
+ if (! ctx) {
+ errno=EINVAL;
+ return -1;
+ }
+
*sid = NULL;
hvalue = sidtab_hash(ctx);
diff --git libselinux-2.5-rc1/src/canonicalize_context.c libselinux-2.5-rc1/src/canonicalize_context.c
index 7cf3139..364a746 100644
--- libselinux-2.5-rc1/src/canonicalize_context.c
+++ libselinux-2.5-rc1/src/canonicalize_context.c
@@ -17,6 +17,11 @@ int security_canonicalize_context_raw(const char * con,
size_t size;
int fd, ret;
+ if (! con) {
+ errno=EINVAL;
+ return -1;
+ }
+
if (!selinux_mnt) {
errno = ENOENT;
return -1;
diff --git libselinux-2.5-rc1/src/check_context.c libselinux-2.5-rc1/src/check_context.c
index 52063fa..234749c 100644
--- libselinux-2.5-rc1/src/check_context.c
+++ libselinux-2.5-rc1/src/check_context.c
@@ -14,6 +14,11 @@ int security_check_context_raw(const char * con)
char path[PATH_MAX];
int fd, ret;
+ if (! con) {
+ errno=EINVAL;
+ return -1;
+ }
+
if (!selinux_mnt) {
errno = ENOENT;
return -1;
diff --git libselinux-2.5-rc1/src/compute_av.c libselinux-2.5-rc1/src/compute_av.c
index 937e5c3..35ace7f 100644
--- libselinux-2.5-rc1/src/compute_av.c
+++ libselinux-2.5-rc1/src/compute_av.c
@@ -26,6 +26,11 @@ int security_compute_av_flags_raw(const char * scon,
return -1;
}
+ if ((! scon) || (! tcon)) {
+ errno=EINVAL;
+ return -1;
+ }
+
snprintf(path, sizeof path, "%s/access", selinux_mnt);
fd = open(path, O_RDWR);
if (fd < 0)
diff --git libselinux-2.5-rc1/src/compute_create.c libselinux-2.5-rc1/src/compute_create.c
index 9559d42..14a65d1 100644
--- libselinux-2.5-rc1/src/compute_create.c
+++ libselinux-2.5-rc1/src/compute_create.c
@@ -64,6 +64,11 @@ int security_compute_create_name_raw(const char * scon,
return -1;
}
+ if ((! scon) || (! tcon)) {
+ errno=EINVAL;
+ return -1;
+ }
+
snprintf(path, sizeof path, "%s/create", selinux_mnt);
fd = open(path, O_RDWR);
if (fd < 0)
diff --git libselinux-2.5-rc1/src/compute_member.c libselinux-2.5-rc1/src/compute_member.c
index 1fc7e41..065d996 100644
--- libselinux-2.5-rc1/src/compute_member.c
+++ libselinux-2.5-rc1/src/compute_member.c
@@ -25,6 +25,11 @@ int security_compute_member_raw(const char * scon,
return -1;
}
+ if ((! scon) || (! tcon)) {
+ errno=EINVAL;
+ return -1;
+ }
+
snprintf(path, sizeof path, "%s/member", selinux_mnt);
fd = open(path, O_RDWR);
if (fd < 0)
diff --git libselinux-2.5-rc1/src/compute_relabel.c libselinux-2.5-rc1/src/compute_relabel.c
index 4615aee..cc77f36 100644
--- libselinux-2.5-rc1/src/compute_relabel.c
+++ libselinux-2.5-rc1/src/compute_relabel.c
@@ -25,6 +25,11 @@ int security_compute_relabel_raw(const char * scon,
return -1;
}
+ if ((! scon) || (! tcon)) {
+ errno=EINVAL;
+ return -1;
+ }
+
snprintf(path, sizeof path, "%s/relabel", selinux_mnt);
fd = open(path, O_RDWR);
if (fd < 0)
diff --git libselinux-2.5-rc1/src/compute_user.c libselinux-2.5-rc1/src/compute_user.c
index b37c5d3..7703c26 100644
--- libselinux-2.5-rc1/src/compute_user.c
+++ libselinux-2.5-rc1/src/compute_user.c
@@ -24,6 +24,11 @@ int security_compute_user_raw(const char * scon,
return -1;
}
+ if (! scon) {
+ errno=EINVAL;
+ return -1;
+ }
+
snprintf(path, sizeof path, "%s/user", selinux_mnt);
fd = open(path, O_RDWR);
if (fd < 0)
diff --git libselinux-2.5-rc1/src/fsetfilecon.c libselinux-2.5-rc1/src/fsetfilecon.c
index 52707d0..0cbe12d 100644
--- libselinux-2.5-rc1/src/fsetfilecon.c
+++ libselinux-2.5-rc1/src/fsetfilecon.c
@@ -9,8 +9,12 @@
int fsetfilecon_raw(int fd, const char * context)
{
- int rc = fsetxattr(fd, XATTR_NAME_SELINUX, context, strlen(context) + 1,
- 0);
+ int rc;
+ if (! context) {
+ errno=EINVAL;
+ return -1;
+ }
+ rc = fsetxattr(fd, XATTR_NAME_SELINUX, context, strlen(context) + 1, 0);
if (rc < 0 && errno == ENOTSUP) {
char * ccontext = NULL;
int err = errno;
diff --git libselinux-2.5-rc1/src/label_android_property.c libselinux-2.5-rc1/src/label_android_property.c
index fea1f8f..290b438 100644
--- libselinux-2.5-rc1/src/label_android_property.c
+++ libselinux-2.5-rc1/src/label_android_property.c
@@ -89,10 +89,21 @@ static int process_line(struct selabel_handle *rec,
struct saved_data *data = (struct saved_data *)rec->data;
spec_t *spec_arr = data->spec_arr;
unsigned int nspec = data->nspec;
+ const char *errbuf = NULL;
- items = read_spec_entries(line_buf, 2, &prop, &context);
- if (items <= 0)
+ items = read_spec_entries(line_buf, &errbuf, 2, &prop, &context);
+ if (items < 0) {
+ items = errno;
+ selinux_log(SELINUX_ERROR,
+ "%s: line %u error due to: %s\n", path,
+ lineno, errbuf ?: strerror(errno));
+ errno = items;
+ return -1;
+ }
+
+ if (items == 0)
return items;
+
if (items != 2) {
selinux_log(SELINUX_ERROR,
"%s: line %u is missing fields\n", path,
diff --git libselinux-2.5-rc1/src/label_file.h libselinux-2.5-rc1/src/label_file.h
index beb1fc2..72fed1f 100644
--- libselinux-2.5-rc1/src/label_file.h
+++ libselinux-2.5-rc1/src/label_file.h
@@ -1,6 +1,9 @@
#ifndef _SELABEL_FILE_H_
#define _SELABEL_FILE_H_
+#include <errno.h>
+#include <string.h>
+
#include <sys/stat.h>
#include "callbacks.h"
@@ -390,8 +393,17 @@ static inline int process_line(struct selabel_handle *rec,
unsigned int nspec = data->nspec;
const char *errbuf = NULL;
- items = read_spec_entries(line_buf, 3, &regex, &type, &context);
- if (items <= 0)
+ items = read_spec_entries(line_buf, &errbuf, 3, &regex, &type, &context);
+ if (items < 0) {
+ rc = errno;
+ selinux_log(SELINUX_ERROR,
+ "%s: line %u error due to: %s\n", path,
+ lineno, errbuf ?: strerror(errno));
+ errno = rc;
+ return -1;
+ }
+
+ if (items == 0)
return items;
if (items < 2) {
diff --git libselinux-2.5-rc1/src/label_internal.h libselinux-2.5-rc1/src/label_internal.h
index cefa80b..aa48fff 100644
--- libselinux-2.5-rc1/src/label_internal.h
+++ libselinux-2.5-rc1/src/label_internal.h
@@ -140,6 +140,6 @@ compat_validate(struct selabel_handle *rec,
* The read_spec_entries function may be used to
* replace sscanf to read entries from spec files.
*/
-extern int read_spec_entries(char *line_buf, int num_args, ...);
+extern int read_spec_entries(char *line_buf, const char **errbuf, int num_args, ...);
#endif /* _SELABEL_INTERNAL_H_ */
diff --git libselinux-2.5-rc1/src/label_support.c libselinux-2.5-rc1/src/label_support.c
index 324dc51..26f9ef1 100644
--- libselinux-2.5-rc1/src/label_support.c
+++ libselinux-2.5-rc1/src/label_support.c
@@ -10,14 +10,19 @@
#include <string.h>
#include <stdio.h>
#include <errno.h>
+#include <errno.h>
#include "label_internal.h"
/*
- * The read_spec_entries and read_spec_entry functions may be used to
- * replace sscanf to read entries from spec files. The file and
- * property services now use these.
+ * Read an entry from a spec file (e.g. file_contexts)
+ * entry - Buffer to allocate for the entry.
+ * ptr - current location of the line to be processed.
+ * returns - 0 on success and *entry is set to be a null
+ * terminated value. On Error it returns -1 and
+ * errno will be set.
+ *
*/
-static inline int read_spec_entry(char **entry, char **ptr, int *len)
+static inline int read_spec_entry(char **entry, char **ptr, int *len, const char **errbuf)
{
*entry = NULL;
char *tmp_buf = NULL;
@@ -29,6 +34,11 @@ static inline int read_spec_entry(char **entry, char **ptr, int *len)
*len = 0;
while (!isspace(**ptr) && **ptr != '\0') {
+ if (!isascii(**ptr)) {
+ errno = EINVAL;
+ *errbuf = "Non-ASCII characters found";
+ return -1;
+ }
(*ptr)++;
(*len)++;
}
@@ -44,18 +54,23 @@ static inline int read_spec_entry(char **entry, char **ptr, int *len)
/*
* line_buf - Buffer containing the spec entries .
+ * errbuf - Double pointer used for passing back specific error messages.
* num_args - The number of spec parameter entries to process.
* ... - A 'char **spec_entry' for each parameter.
- * returns - The number of items processed.
+ * returns - The number of items processed. On error, it returns -1 with errno
+ * set and may set errbuf to a specific error message.
*
* This function calls read_spec_entry() to do the actual string processing.
+ * As such, can return anything from that function as well.
*/
-int hidden read_spec_entries(char *line_buf, int num_args, ...)
+int hidden read_spec_entries(char *line_buf, const char **errbuf, int num_args, ...)
{
char **spec_entry, *buf_p;
int len, rc, items, entry_len = 0;
va_list ap;
+ *errbuf = NULL;
+
len = strlen(line_buf);
if (line_buf[len - 1] == '\n')
line_buf[len - 1] = '\0';
@@ -85,7 +100,7 @@ int hidden read_spec_entries(char *line_buf, int num_args, ...)
return items;
}
- rc = read_spec_entry(spec_entry, &buf_p, &entry_len);
+ rc = read_spec_entry(spec_entry, &buf_p, &entry_len, errbuf);
if (rc < 0) {
va_end(ap);
return rc;
diff --git libselinux-2.5-rc1/src/lsetfilecon.c libselinux-2.5-rc1/src/lsetfilecon.c
index 1d3b28a..ea6d70b 100644
--- libselinux-2.5-rc1/src/lsetfilecon.c
+++ libselinux-2.5-rc1/src/lsetfilecon.c
@@ -9,8 +9,13 @@
int lsetfilecon_raw(const char *path, const char * context)
{
- int rc = lsetxattr(path, XATTR_NAME_SELINUX, context, strlen(context) + 1,
- 0);
+ int rc;
+ if (! context) {
+ errno=EINVAL;
+ return -1;
+ }
+
+ rc = lsetxattr(path, XATTR_NAME_SELINUX, context, strlen(context) + 1, 0);
if (rc < 0 && errno == ENOTSUP) {
char * ccontext = NULL;
int err = errno;
diff --git libselinux-2.5-rc1/src/matchpathcon.c libselinux-2.5-rc1/src/matchpathcon.c
index 5b495a0..3868711 100644
--- libselinux-2.5-rc1/src/matchpathcon.c
+++ libselinux-2.5-rc1/src/matchpathcon.c
@@ -2,6 +2,7 @@
#include <string.h>
#include <errno.h>
#include <stdio.h>
+#include <syslog.h>
#include "selinux_internal.h"
#include "label_internal.h"
#include "callbacks.h"
@@ -62,7 +63,7 @@ static void
{
va_list ap;
va_start(ap, fmt);
- vfprintf(stderr, fmt, ap);
+ vsyslog(LOG_ERR, fmt, ap);
va_end(ap);
}
diff --git libselinux-2.5-rc1/src/selinux_internal.h libselinux-2.5-rc1/src/selinux_internal.h
index 46566f6..3d3fecf 100644
--- libselinux-2.5-rc1/src/selinux_internal.h
+++ libselinux-2.5-rc1/src/selinux_internal.h
@@ -82,6 +82,7 @@ hidden_proto(selinux_mkload_policy)
hidden_proto(selinux_customizable_types_path)
hidden_proto(selinux_media_context_path)
hidden_proto(selinux_x_context_path)
+ hidden_proto(selinux_openssh_contexts_path)
hidden_proto(selinux_sepgsql_context_path)
hidden_proto(selinux_openssh_contexts_path)
hidden_proto(selinux_systemd_contexts_path)
diff --git libselinux-2.5-rc1/src/selinux_restorecon.c libselinux-2.5-rc1/src/selinux_restorecon.c
new file mode 100644
index 0000000..17ed6fe
--- /dev/null
+++ libselinux-2.5-rc1/src/selinux_restorecon.c
@@ -0,0 +1,486 @@
+/*
+ * The majority of this code is from Android's
+ * external/libselinux/src/android.c and upstream
+ * selinux/policycoreutils/setfiles/restorecon.c
+ *
+ * See selinux_restorecon(3) for details.
+ */
+
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <fts.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/xattr.h>
+#include <sys/vfs.h>
+#include <linux/magic.h>
+#include <libgen.h>
+#include <selinux/selinux.h>
+#include <selinux/context.h>
+#include <selinux/label.h>
+#include <selinux/restorecon.h>
+
+#include "callbacks.h"
+#include "selinux_internal.h"
+
+#define RESTORECON_LAST "security.restorecon_last"
+
+#define SYS_PATH "/sys"
+#define SYS_PREFIX SYS_PATH "/"
+
+static struct selabel_handle *fc_sehandle = NULL;
+static unsigned char *fc_digest = NULL;
+static size_t fc_digest_len = 0;
+static const char **fc_exclude_list = NULL;
+static size_t fc_count = 0;
+#define STAR_COUNT 1000
+
+static void restorecon_init(void)
+{
+ struct selabel_handle *sehandle = NULL;
+
+ if (!fc_sehandle) {
+ sehandle = selinux_restorecon_default_handle();
+ selinux_restorecon_set_sehandle(sehandle);
+ }
+}
+
+static pthread_once_t fc_once = PTHREAD_ONCE_INIT;
+
+
+static int check_excluded(const char *file)
+{
+ int i;
+
+ for (i = 0; fc_exclude_list[i]; i++) {
+ if (strcmp(file, fc_exclude_list[i]) == 0)
+ return 1;
+ }
+ return 0;
+}
+
+/* Called if SELINUX_RESTORECON_SET_SPECFILE_CTX is not set to check if
+ * the type components differ, updating newtypecon if so. */
+static int compare_types(char *curcon, char *newcon, char **newtypecon)
+{
+ int types_differ = 0;
+ context_t cona;
+ context_t conb;
+ int rc = 0;
+
+ cona = context_new(curcon);
+ if (!cona) {
+ rc = -1;
+ goto out;
+ }
+ conb = context_new(newcon);
+ if (!conb) {
+ context_free(cona);
+ rc = -1;
+ goto out;
+ }
+
+ types_differ = strcmp(context_type_get(cona), context_type_get(conb));
+ if (types_differ) {
+ rc |= context_user_set(conb, context_user_get(cona));
+ rc |= context_role_set(conb, context_role_get(cona));
+ rc |= context_range_set(conb, context_range_get(cona));
+ if (!rc) {
+ *newtypecon = strdup(context_str(conb));
+ if (!*newtypecon) {
+ rc = -1;
+ goto err;
+ }
+ }
+ }
+
+err:
+ context_free(cona);
+ context_free(conb);
+out:
+ return rc;
+}
+
+static int restorecon_sb(const char *pathname, const struct stat *sb,
+ bool nochange, bool verbose,
+ bool progress, bool specctx)
+{
+ char *newcon = NULL;
+ char *curcon = NULL;
+ char *newtypecon = NULL;
+ int rc = 0;
+ bool updated = false;
+
+ if (selabel_lookup_raw(fc_sehandle, &newcon, pathname, sb->st_mode) < 0)
+ return 0; /* no match, but not an error */
+
+ if (lgetfilecon_raw(pathname, &curcon) < 0) {
+ if (errno != ENODATA)
+ goto err;
+
+ curcon = NULL;
+ }
+
+ if (progress) {
+ fc_count++;
+ if (fc_count % STAR_COUNT == 0) {
+ fprintf(stdout, "*");
+ fflush(stdout);
+ }
+ }
+
+ if (strcmp(curcon, newcon) != 0) {
+ if (!specctx && curcon &&
+ (is_context_customizable(curcon) > 0)) {
+ if (verbose) {
+ selinux_log(SELINUX_INFO,
+ "%s not reset as customized by admin to %s\n",
+ pathname, curcon);
+ goto out;
+ }
+ }
+
+ if (!specctx && curcon) {
+ /* If types different then update newcon. */
+ rc = compare_types(curcon, newcon, &newtypecon);
+ if (rc)
+ goto err;
+
+ if (newtypecon) {
+ freecon(newcon);
+ newcon = newtypecon;
+ } else {
+ goto out;
+ }
+ }
+
+ if (!nochange) {
+ if (lsetfilecon(pathname, newcon) < 0)
+ goto err;
+ updated = true;
+ }
+
+ if (verbose)
+ selinux_log(SELINUX_INFO,
+ "%s %s from %s to %s\n",
+ updated ? "Relabeled" : "Would relabel",
+ pathname, curcon, newcon);
+ }
+
+out:
+ rc = 0;
+out1:
+ freecon(curcon);
+ freecon(newcon);
+ return rc;
+err:
+ selinux_log(SELINUX_ERROR,
+ "Could not set context for %s: %s\n",
+ pathname, strerror(errno));
+ rc = -1;
+ goto out1;
+}
+
+/*
+ * Public API
+ */
+
+/* selinux_restorecon(3) - Main function that is responsible for labeling */
+int selinux_restorecon(const char *pathname_orig,
+ unsigned int restorecon_flags)
+{
+ bool ignore = (restorecon_flags &
+ SELINUX_RESTORECON_IGNORE_DIGEST) ? true : false;
+ bool nochange = (restorecon_flags &
+ SELINUX_RESTORECON_NOCHANGE) ? true : false;
+ bool verbose = (restorecon_flags &
+ SELINUX_RESTORECON_VERBOSE) ? true : false;
+ bool progress = (restorecon_flags &
+ SELINUX_RESTORECON_PROGRESS) ? true : false;
+ bool recurse = (restorecon_flags &
+ SELINUX_RESTORECON_RECURSE) ? true : false;
+ bool specctx = (restorecon_flags &
+ SELINUX_RESTORECON_SET_SPECFILE_CTX) ? true : false;
+ bool userealpath = (restorecon_flags &
+ SELINUX_RESTORECON_REALPATH) ? true : false;
+ bool xdev = (restorecon_flags &
+ SELINUX_RESTORECON_XDEV) ? true : false;
+ bool issys;
+ bool setrestoreconlast = true; /* TRUE = set xattr RESTORECON_LAST
+ * FALSE = don't use xattr */
+ struct stat sb;
+ struct statfs sfsb;
+ FTS *fts;
+ FTSENT *ftsent;
+ char *pathname = NULL, *pathdnamer = NULL, *pathdname, *pathbname;
+ char *paths[2] = { NULL , NULL };
+ int fts_flags;
+ int error, sverrno;
+ char *xattr_value = NULL;
+ ssize_t size;
+
+ if (verbose && progress)
+ verbose = false;
+
+ __selinux_once(fc_once, restorecon_init);
+
+ if (!fc_sehandle)
+ return -1;
+
+ if (fc_digest_len) {
+ xattr_value = malloc(fc_digest_len);
+ if (!xattr_value)
+ return -1;
+ }
+
+ /*
+ * Convert passed-in pathname to canonical pathname by resolving
+ * realpath of containing dir, then appending last component name.
+ */
+ if (userealpath) {
+ pathbname = basename((char *)pathname_orig);
+ if (!strcmp(pathbname, "/") || !strcmp(pathbname, ".") ||
+ !strcmp(pathbname, "..")) {
+ pathname = realpath(pathname_orig, NULL);
+ if (!pathname)
+ goto realpatherr;
+ } else {
+ pathdname = dirname((char *)pathname_orig);
+ pathdnamer = realpath(pathdname, NULL);
+ if (!pathdnamer)
+ goto realpatherr;
+ if (!strcmp(pathdnamer, "/"))
+ error = asprintf(&pathname, "/%s", pathbname);
+ else
+ error = asprintf(&pathname, "%s/%s",
+ pathdnamer, pathbname);
+ if (error < 0)
+ goto oom;
+ }
+ } else {
+ pathname = strdup(pathname_orig);
+ if (!pathname)
+ goto oom;
+ }
+
+ paths[0] = pathname;
+ issys = (!strcmp(pathname, SYS_PATH) ||
+ !strncmp(pathname, SYS_PREFIX,
+ sizeof(SYS_PREFIX) - 1)) ? true : false;
+
+ if (lstat(pathname, &sb) < 0) {
+ error = -1;
+ goto cleanup;
+ }
+
+ /* Ignore restoreconlast if not a directory */
+ if ((sb.st_mode & S_IFDIR) != S_IFDIR)
+ setrestoreconlast = false;
+
+ if (!recurse) {
+ error = restorecon_sb(pathname, &sb, nochange, verbose,
+ progress, specctx);
+ goto cleanup;
+ }
+
+ /* Ignore restoreconlast on /sys */
+ if (issys)
+ setrestoreconlast = false;
+
+ /* Ignore restoreconlast on in-memory filesystems */
+ if (statfs(pathname, &sfsb) == 0) {
+ if (sfsb.f_type == RAMFS_MAGIC || sfsb.f_type == TMPFS_MAGIC)
+ setrestoreconlast = false;
+ }
+
+ if (setrestoreconlast) {
+ size = getxattr(pathname, RESTORECON_LAST, xattr_value,
+ fc_digest_len);
+
+ if (!ignore && size == fc_digest_len &&
+ memcmp(fc_digest, xattr_value, fc_digest_len)
+ == 0) {
+ selinux_log(SELINUX_INFO,
+ "Skipping restorecon as matching digest on: %s\n",
+ pathname);
+ error = 0;
+ goto cleanup;
+ }
+ }
+
+ if (xdev)
+ fts_flags = FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV;
+ else
+ fts_flags = FTS_PHYSICAL | FTS_NOCHDIR;
+
+ fts = fts_open(paths, fts_flags, NULL);
+ if (!fts) {
+ error = -1;
+ goto cleanup;
+ }
+
+ error = 0;
+ while ((ftsent = fts_read(fts)) != NULL) {
+ switch (ftsent->fts_info) {
+ case FTS_DC:
+ selinux_log(SELINUX_ERROR,
+ "Directory cycle on %s.\n",
+ ftsent->fts_path);
+ errno = ELOOP;
+ error = -1;
+ goto out;
+ case FTS_DP:
+ continue;
+ case FTS_DNR:
+ selinux_log(SELINUX_ERROR,
+ "Could not read %s: %s.\n",
+ ftsent->fts_path,
+ strerror(ftsent->fts_errno));
+ fts_set(fts, ftsent, FTS_SKIP);
+ continue;
+ case FTS_NS:
+ selinux_log(SELINUX_ERROR,
+ "Could not stat %s: %s.\n",
+ ftsent->fts_path,
+ strerror(ftsent->fts_errno));
+ fts_set(fts, ftsent, FTS_SKIP);
+ continue;
+ case FTS_ERR:
+ selinux_log(SELINUX_ERROR,
+ "Error on %s: %s.\n",
+ ftsent->fts_path,
+ strerror(ftsent->fts_errno));
+ fts_set(fts, ftsent, FTS_SKIP);
+ continue;
+ case FTS_D:
+ if (issys && !selabel_partial_match(fc_sehandle,
+ ftsent->fts_path)) {
+ fts_set(fts, ftsent, FTS_SKIP);
+ continue;
+ }
+ /* fall through */
+ default:
+ if (fc_exclude_list) {
+ if (check_excluded(ftsent->fts_path)) {
+ fts_set(fts, ftsent, FTS_SKIP);
+ continue;
+ }
+ }
+
+ error |= restorecon_sb(ftsent->fts_path,
+ ftsent->fts_statp, nochange,
+ verbose, progress, specctx);
+ break;
+ }
+ }
+
+ /* Labeling successful. Mark the top level directory as completed. */
+ if (setrestoreconlast && !nochange && !error) {
+ error = setxattr(pathname, RESTORECON_LAST, fc_digest,
+ fc_digest_len, 0);
+ if (!error && verbose)
+ selinux_log(SELINUX_INFO,
+ "Updated digest for: %s\n", pathname);
+ }
+
+out:
+ sverrno = errno;
+ (void) fts_close(fts);
+ errno = sverrno;
+cleanup:
+ free(pathdnamer);
+ free(pathname);
+ free(xattr_value);
+ return error;
+oom:
+ sverrno = errno;
+ selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __func__);
+ errno = sverrno;
+ error = -1;
+ goto cleanup;
+realpatherr:
+ sverrno = errno;
+ selinux_log(SELINUX_ERROR,
+ "SELinux: Could not get canonical path for %s restorecon: %s.\n",
+ pathname_orig, strerror(errno));
+ errno = sverrno;
+ error = -1;
+ goto cleanup;
+}
+
+/* selinux_restorecon_set_sehandle(3) is called to set the global fc handle */
+void selinux_restorecon_set_sehandle(struct selabel_handle *hndl)
+{
+ char **specfiles, *sha1_buf = NULL;
+ size_t num_specfiles, i;
+
+ fc_sehandle = (struct selabel_handle *) hndl;
+
+ /* Read digest if requested in selabel_open(3).
+ * If not the set global params. */
+ if (selabel_digest(hndl, &fc_digest, &fc_digest_len,
+ &specfiles, &num_specfiles) < 0) {
+ fc_digest = NULL;
+ fc_digest_len = 0;
+ selinux_log(SELINUX_INFO, "Digest not requested.\n");
+ return;
+ }
+
+ sha1_buf = malloc(fc_digest_len * 2 + 1);
+ if (!sha1_buf) {
+ selinux_log(SELINUX_ERROR,
+ "Error allocating digest buffer: %s\n",
+ strerror(errno));
+ return;
+ }
+
+ for (i = 0; i < fc_digest_len; i++)
+ sprintf((&sha1_buf[i * 2]), "%02x", fc_digest[i]);
+
+ selinux_log(SELINUX_INFO,
+ "specfiles SHA1 digest: %s\n", sha1_buf);
+ selinux_log(SELINUX_INFO,
+ "calculated using the following specfile(s):\n");
+ if (specfiles) {
+ for (i = 0; i < num_specfiles; i++)
+ selinux_log(SELINUX_INFO,
+ "%s\n", specfiles[i]);
+ }
+ free(sha1_buf);
+}
+
+/* selinux_restorecon_default_handle(3) is called to set the global restorecon
+ * handle by a process if the default params are required. */
+struct selabel_handle *selinux_restorecon_default_handle(void)
+{
+ struct selabel_handle *sehandle;
+
+ struct selinux_opt fc_opts[] = {
+ { SELABEL_OPT_DIGEST, (char *)1 }
+ };
+
+ sehandle = selabel_open(SELABEL_CTX_FILE, fc_opts, 1);
+
+ if (!sehandle) {
+ selinux_log(SELINUX_ERROR,
+ "Error obtaining file context handle: %s\n",
+ strerror(errno));
+ return NULL;
+ }
+
+ return sehandle;
+}
+
+/* selinux_restorecon_set_exclude_list(3) is called to set a NULL terminated
+ * list of files/directories to exclude. */
+void selinux_restorecon_set_exclude_list(const char **exclude_list)
+{
+ fc_exclude_list = exclude_list;
+}
diff --git libselinux-2.5-rc1/src/setfilecon.c libselinux-2.5-rc1/src/setfilecon.c
index d05969c..3f0200e 100644
--- libselinux-2.5-rc1/src/setfilecon.c
+++ libselinux-2.5-rc1/src/setfilecon.c
@@ -9,8 +9,12 @@
int setfilecon_raw(const char *path, const char * context)
{
- int rc = setxattr(path, XATTR_NAME_SELINUX, context, strlen(context) + 1,
- 0);
+ int rc;
+ if (! context) {
+ errno=EINVAL;
+ return -1;
+ }
+ rc = setxattr(path, XATTR_NAME_SELINUX, context, strlen(context) + 1, 0);
if (rc < 0 && errno == ENOTSUP) {
char * ccontext = NULL;
int err = errno;
diff --git libselinux-2.5-rc1/utils/Makefile libselinux-2.5-rc1/utils/Makefile
index cac85c7..cf7af52 100644
--- libselinux-2.5-rc1/utils/Makefile
+++ libselinux-2.5-rc1/utils/Makefile
@@ -30,6 +30,8 @@ TARGETS=$(patsubst %.c,%,$(wildcard *.c))
sefcontext_compile: LDLIBS += -lpcre ../src/libselinux.a -lsepol
+selinux_restorecon: LDLIBS += -lsepol
+
ifeq ($(DISABLE_AVC),y)
UNUSED_TARGETS+=compute_av compute_create compute_member compute_relabel
endif
diff --git libselinux-2.5-rc1/utils/selinux_restorecon.c libselinux-2.5-rc1/utils/selinux_restorecon.c
new file mode 100644
index 0000000..52352c5
--- /dev/null
+++ libselinux-2.5-rc1/utils/selinux_restorecon.c
@@ -0,0 +1,263 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <sepol/sepol.h>
+#include <selinux/label.h>
+#include <selinux/restorecon.h>
+
+static char *policyfile;
+
+static char **exclude_list;
+static int exclude_count;
+
+static int validate_context(char **contextp)
+{
+ char *context = *contextp, *tmpcon;
+
+ if (policyfile) {
+ if (sepol_check_context(context) < 0) {
+ fprintf(stderr, "Invalid context %s\n", context);
+ exit(-1);
+ }
+ } else if (security_canonicalize_context_raw(context, &tmpcon) == 0) {
+ free(context);
+ *contextp = tmpcon;
+ } else if (errno != ENOENT) {
+ fprintf(stderr, "Validate context error: %s\n",
+ strerror(errno));
+ exit(-1);
+ }
+
+ return 0;
+}
+
+static void usage(const char *progname)
+{
+ fprintf(stderr,
+ "\nusage: %s [-FCnRrdei] [-v|-P] [-p policy] [-f specfile] "
+ "pathname ...\n"
+ "Where:\n\t"
+ "-F Set the label to that in specfile.\n\t"
+ " If not set then reset the \"type\" component of the "
+ "label to that\n\t in the specfile.\n\t"
+ "-C Check labels even if the stored SHA1 digest matches\n\t"
+ " the specfiles SHA1 digest.\n\t"
+ "-n Don't change any file labels (passive check).\n\t"
+ "-R Recursively change file and directory labels.\n\t"
+ "-v Show changes in file labels (-v and -P are mutually "
+ " exclusive).\n\t"
+ "-P Show progress by printing \"*\" to stdout every 1000 files.\n\t"
+ "-r Use realpath(3) to convert pathnames to canonical form.\n\t"
+ "-d Prevent descending into directories that have a "
+ "different\n\t device number than the pathname from which "
+ "the descent began.\n\t"
+ "-e Exclude this file/directory (add multiple -e entries).\n\t"
+ "-i Do not set SELABEL_OPT_VALIDATE option in selabel_open(3)"
+ " then call\n\t selinux_restorecon_set_sehandle(3).\n\t"
+ "-p Optional binary policy file (also sets validate context "
+ "option).\n\t"
+ "-f Optional file contexts file.\n\t"
+ "pathname One or more paths to relabel.\n\n",
+ progname);
+ exit(-1);
+}
+
+static void add_exclude(const char *directory)
+{
+ char **tmp_list;
+
+ if (directory == NULL || directory[0] != '/') {
+ fprintf(stderr, "Full path required for exclude: %s.\n",
+ directory);
+ exit(-1);
+ }
+
+ /* Add another two entries, one for directory, and the other to
+ * terminate the list */
+ tmp_list = realloc(exclude_list, sizeof(char *) * (exclude_count + 2));
+ if (!tmp_list) {
+ fprintf(stderr, "ERROR: realloc failed.\n");
+ exit(-1);
+ }
+ exclude_list = tmp_list;
+
+ exclude_list[exclude_count] = strdup(directory);
+ if (!exclude_list[exclude_count]) {
+ fprintf(stderr, "ERROR: strdup failed.\n");
+ exit(-1);
+ }
+ exclude_count++;
+ exclude_list[exclude_count] = NULL;
+}
+
+int main(int argc, char **argv)
+{
+ int opt, i;
+ unsigned int restorecon_flags = 0;
+ char *path = NULL, *digest = NULL, *validate = NULL;
+ FILE *policystream;
+ bool ignore_digest = false, require_selinux = true;
+ bool verbose = false, progress = false;
+
+ struct selabel_handle *hnd = NULL;
+ struct selinux_opt selabel_option[] = {
+ { SELABEL_OPT_PATH, path },
+ { SELABEL_OPT_DIGEST, digest },
+ { SELABEL_OPT_VALIDATE, validate }
+ };
+
+ if (argc < 2)
+ usage(argv[0]);
+
+ exclude_list = NULL;
+ exclude_count = 0;
+
+ while ((opt = getopt(argc, argv, "iFCnRvPrde:f:p:")) > 0) {
+ switch (opt) {
+ case 'F':
+ restorecon_flags |=
+ SELINUX_RESTORECON_SET_SPECFILE_CTX;
+ break;
+ case 'C':
+ restorecon_flags |=
+ SELINUX_RESTORECON_IGNORE_DIGEST;
+ break;
+ case 'n':
+ restorecon_flags |= SELINUX_RESTORECON_NOCHANGE;
+ break;
+ case 'R':
+ restorecon_flags |= SELINUX_RESTORECON_RECURSE;
+ break;
+ case 'v':
+ if (progress) {
+ fprintf(stderr,
+ "Progress and Verbose are mutually exclusive\n");
+ exit(-1);
+ }
+ verbose = true;
+ restorecon_flags |= SELINUX_RESTORECON_VERBOSE;
+ break;
+ case 'P':
+ if (verbose) {
+ fprintf(stderr,
+ "Progress and Verbose are mutually exclusive\n");
+ exit(-1);
+ }
+ progress = true;
+ restorecon_flags |= SELINUX_RESTORECON_PROGRESS;
+ break;
+ case 'r':
+ restorecon_flags |= SELINUX_RESTORECON_REALPATH;
+ break;
+ case 'd':
+ restorecon_flags |= SELINUX_RESTORECON_XDEV;
+ break;
+ case 'e':
+ add_exclude(optarg);
+ break;
+ case 'p':
+ policyfile = optarg;
+
+ policystream = fopen(policyfile, "r");
+ if (!policystream) {
+ fprintf(stderr,
+ "ERROR: opening %s: %s\n",
+ policyfile, strerror(errno));
+ exit(-1);
+ }
+
+ if (sepol_set_policydb_from_file(policystream) < 0) {
+ fprintf(stderr,
+ "ERROR: reading policy %s: %s\n",
+ policyfile, strerror(errno));
+ exit(-1);
+ }
+ fclose(policystream);
+
+ selinux_set_callback(SELINUX_CB_VALIDATE,
+ (union selinux_callback)&validate_context);
+ require_selinux = false;
+ break;
+ case 'f':
+ path = optarg;
+ break;
+ case 'i':
+ ignore_digest = true;
+ break;
+ default:
+ usage(argv[0]);
+ }
+ }
+
+ if (require_selinux && (is_selinux_enabled() <= 0)) {
+ fprintf(stderr,
+ "SELinux must be enabled to perform this operation.\n");
+ exit(-1);
+ }
+
+ if (optind >= argc) {
+ fprintf(stderr, "No pathname specified\n");
+ exit(-1);
+ }
+
+ /* If any of these set then do our own selabel_open and pass
+ * handle to selinux_restorecon */
+ if (ignore_digest || path || policyfile) {
+ if (path)
+ selabel_option[0].value = path;
+ else
+ selabel_option[0].value = NULL;
+
+ if (ignore_digest)
+ selabel_option[1].value = NULL;
+ else
+ selabel_option[1].value = (char *)1;
+
+ if (policyfile) /* Validate */
+ selabel_option[2].value = (char *)1;
+ else
+ selabel_option[2].value = NULL;
+
+ hnd = selabel_open(SELABEL_CTX_FILE, selabel_option, 3);
+ if (!hnd) {
+ switch (errno) {
+ case EOVERFLOW:
+ fprintf(stderr, "ERROR: Number of specfiles or"
+ " specfile buffer caused an overflow.\n");
+ break;
+ default:
+ fprintf(stderr, "ERROR: selabel_open: %s\n",
+ strerror(errno));
+ }
+ exit(-1);
+ }
+ selinux_restorecon_set_sehandle(hnd);
+ }
+
+ if (exclude_list)
+ selinux_restorecon_set_exclude_list
+ ((const char **)exclude_list);
+
+ /* Call restorecon for each path in list */
+ for (i = optind; i < argc; i++) {
+ if (selinux_restorecon(argv[i], restorecon_flags) < 0) {
+ fprintf(stderr, "ERROR: selinux_restorecon: %s\n",
+ strerror(errno));
+ exit(-1);
+ }
+ }
+
+ if (exclude_list) {
+ for (i = 0; exclude_list[i]; i++)
+ free(exclude_list[i]);
+ free(exclude_list);
+ }
+
+ if (hnd)
+ selabel_close(hnd);
+
+ return 0;
+}