e58e944835
Update to upstream rc1 release 2016-01-07
2092 lines
55 KiB
Diff
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, ®ex, &type, &context);
|
|
- if (items <= 0)
|
|
+ items = read_spec_entries(line_buf, &errbuf, 3, ®ex, &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;
|
|
+}
|