aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2010-02-22 15:01:17 +0000
committerDavid Howells <dhowells@redhat.com>2010-02-22 15:01:17 +0000
commit98521a2ba45cc8de17b2d131609c0e1c67ce6dee (patch)
tree0a9075fe20a4f43ad47f5c2763b3da880e1f947f
parentf1231e06dadede4024adecd8a5f41df90a4ccd54 (diff)
downloadcachefilesd-98521a2ba45cc8de17b2d131609c0e1c67ce6dee.tar.gz
cachefilesd historical revision 0.8v0.8
Made cachefilesd ask the kernel whether cullable objects are in use and omit them from the cull table if they are. Made the size of cachefilesd's culling tables configurable. Updated the manual pages. Documented SELinux interaction. Include SELinux policy for cachefilesd. Fixed typo that was causing the howto.txt not to be installed. Use /dev/cachefiles if it present in preference to /proc/fs/cachefiles. Use poll rather than SIGURG on /dev/cachefilesd.
-rw-r--r--Makefile26
-rw-r--r--README96
-rw-r--r--cachefilesd.810
-rw-r--r--cachefilesd.c175
-rw-r--r--cachefilesd.conf.520
-rwxr-xr-xcachefilesd.initd11
-rw-r--r--howto.txt17
-rw-r--r--redhat/cachefilesd.spec122
-rw-r--r--selinux/cachefilesd.fc28
-rw-r--r--selinux/cachefilesd.if41
-rw-r--r--selinux/cachefilesd.te119
-rw-r--r--selinux/move-cache.txt85
12 files changed, 663 insertions, 87 deletions
diff --git a/Makefile b/Makefile
index 6ceb019..15a8445 100644
--- a/Makefile
+++ b/Makefile
@@ -1,41 +1,32 @@
CFLAGS := -g -O2 -Wall
INSTALL := install
DESTDIR :=
-MAJOR := 0
-MINOR := 4
-VERSION := $(MAJOR).$(MINOR)
-BUILDFOR :=
+BUILDFOR :=
ETCDIR := /etc
BINDIR := /bin
SBINDIR := /sbin
-LIBDIR := /lib
-USRLIBDIR := /usr/lib
-SHAREDIR := /usr/share/keyutils
-INCLUDEDIR := /usr/include
-ARLIB := libkeyutils.a
-DEVELLIB := libkeyutils.so
-SONAME := libkeyutils.so.$(MAJOR)
-LIBNAME := libkeyutils-$(VERSION).so
LNS := ln -sf
ifeq ($(BUILDFOR),32-bit)
CFLAGS += -m32
-LIBDIR := /lib
-USRLIBDIR := /usr/lib
else
ifeq ($(BUILDFOR),64-bit)
CFLAGS += -m64
-LIBDIR := /lib64
-USRLIBDIR := /usr/lib64
endif
endif
+#
+# building
+#
all: cachefilesd
cachefilesd: cachefilesd.c Makefile
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
+#
+# installation
+#
MAN5 := $(DESTDIR)/usr/share/man/man5
MAN8 := $(DESTDIR)/usr/share/man/man8
@@ -45,6 +36,9 @@ install: all
$(INSTALL) -D -m 0644 cachefilesd.conf.5 $(MAN5)/cachefilesd.conf.5
$(INSTALL) -D -m 0644 cachefilesd.8 $(MAN8)/cachefilesd.8
+#
+# clean up
+#
clean:
$(RM) cachefilesd
$(RM) *.o *~
diff --git a/README b/README
index c320aa7..9c091e6 100644
--- a/README
+++ b/README
@@ -14,6 +14,12 @@ Contents:
(*) Things to avoid.
+ (*) Cache culling.
+
+ (*) Cache structure.
+
+ (*) Security model and SELinux.
+
========
OVERVIEW
@@ -96,6 +102,18 @@ set up cache ready for use. The following script commands are available:
Specify a tag to FS-Cache to use in distinguishing multiple caches.
Optional. The default is "CacheFiles".
+ (*) culltable <log2size>
+
+ Specify the size of the tables holding the lists of cullable objects in
+ the cache. The bigger the number, the faster and more smoothly that
+ culling can proceed when there are many objects in the cache, but the
+ more memory will be consumed by cachefilesd.
+
+ The quantity is specified as log2 of the size actually required, for
+ example 12 indicates a table of 4096 entries and 13 indicates 8192
+ entries. The permissible values are between 12 and 20, the latter
+ indicating 1048576 entries. The default is 12.
+
(*) debug <mask>
Specify a numeric bitmask to control debugging in the kernel module.
@@ -284,3 +302,81 @@ or retire them.
Note that CacheFiles will erase from the cache any file it doesn't recognise or
any file of an incorrect type (such as a FIFO file or a device file).
+
+
+==========================
+SECURITY MODEL AND SELINUX
+==========================
+
+CacheFiles is implemented to deal properly with the LSM security features of
+the Linux kernel and the SELinux facility.
+
+One of the problems that CacheFiles faces is that it is generally acting on
+behalf of a process that is in a security context that is not appropriate for
+accessing the cache - either because the files in the cache are inaccessible to
+that process, or because if the process creates a file in the cache, it'll be
+inaccessible to other processes.
+
+The way CacheFiles works is to temporarily change the security context (fsuid,
+fsgid and actor security label) that the process acts as - without changing the
+security context of the process when it the target of an operation performed by
+some other process (so signalling and suchlike still work correctly).
+
+
+When the CacheFiles module is asked to bind to its cache, it:
+
+ (1) Finds the security label attached to the root cache directory and uses
+ that as the security label with which it will create files. By default,
+ this is:
+
+ cachefiles_var_t
+
+ (2) Finds the security label of the process which issued the bind request
+ (presumed to be the cachefilesd daemon), which by default will be:
+
+ cachefilesd_t
+
+ and asks LSM to supply a security ID as which it should act given the
+ daemon's label. By default, this will be:
+
+ cachefiles_kernel_t
+
+ SELinux transitions the daemon's security ID to the module's security ID
+ based on a rule of this form in the policy.
+
+ type_transition <daemon's-ID> kernel_t : process <module's-ID>;
+
+ For instance:
+
+ type_transition cachefilesd_t kernel_t : process cachefiles_kernel_t;
+
+
+The module's security ID gives it permission to create, move and remove files
+and directories in the cache, to find and access directories and files in the
+cache, to set and access extended attributes on cache objects, and to read and
+write files in the cache.
+
+The daemon's security ID gives it only a very restricted set of permissions: it
+may scan directories, stat files and erase files and directories. It may
+not read or write files in the cache, and so it is precluded from accessing the
+data cached therein; nor is it permitted to create new files in the cache.
+
+
+The policy source files are installed for reference as:
+
+ /usr/share/doc/cachefilesd-selinux-*/cachefilesd.te
+ /usr/share/doc/cachefilesd-selinux-*/cachefilesd.fc
+ /usr/share/doc/cachefilesd-selinux-*/cachefilesd.if
+
+By default, the cache is located in /var/fscache, but if it is desirable that
+it should be elsewhere, than either the above policy files must be altered, or
+an auxiliary policy must be installed to label the alternate location of the
+cache.
+
+For instructions on how to add an auxiliary policy to enable the cache to be
+located elsewhere when SELinux is in enforcing mode, please see:
+
+ /usr/share/doc/cachefilesd-*/move-cache.txt
+
+When the cachefilesd rpm is installed; alternatively, the document can be found
+in the sources.
diff --git a/cachefilesd.8 b/cachefilesd.8
index 07335e0..25a28c8 100644
--- a/cachefilesd.8
+++ b/cachefilesd.8
@@ -7,7 +7,7 @@
.\" as published by the Free Software Foundation; either version
.\" 2 of the License, or (at your option) any later version.
.\"
-.TH cachefilesd 8 "11 July 2006"
+.TH cachefilesd 8 "14 November 2006"
.SH NAME
cachefilesd \- CacheFiles userspace management daemon
.SH SYNOPSIS
@@ -18,23 +18,27 @@ network filesystems such a AFS and NFS to cache data locally on disk.
.P
The README file should be read before attempting to configure this facility:
.IP
-/usr/share/docs/cachefilesd-*/README
+/usr/share/doc/cachefilesd-*/README
.SH OPTIONS
.TP
.B -d
Turn on debugging mode (message written to stderr).
+.TP
.B -s
Don't use syslog.
.TP
.B -n
Don't daemonise.
.TP
+.BI "-p <pidfile>"
+Use an alternate PID file to /var/run/cachefilesd.pid.
+.TP
.BI "-f <configfile>"
Read the alternate configuration files.
.SH FILES
.BR /etc/cachefilesd.conf
.SH SEE ALSO
-\fBcachefilesd.conf\fR(5), /usr/share/docs/cachefilesd-*/README
+\fBcachefilesd.conf\fR(5), /usr/share/doc/cachefilesd-*/README
.SH AUTHORS
.br
David Howells <dhowells@redhat.com>
diff --git a/cachefilesd.c b/cachefilesd.c
index 5390f2a..605251b 100644
--- a/cachefilesd.c
+++ b/cachefilesd.c
@@ -42,6 +42,7 @@
#include <syslog.h>
#include <dirent.h>
#include <time.h>
+#include <poll.h>
#include <sys/inotify.h>
#include <sys/time.h>
#include <sys/vfs.h>
@@ -87,9 +88,9 @@ static int jumpstart_scan = 0;
* - we have two tables: one we're building and one that's full of ready to be
* culled objects
*/
-#define CULLTABLE_SIZE 4096
-static struct object *cullbuild[CULLTABLE_SIZE];
-static struct object *cullready[CULLTABLE_SIZE];
+static unsigned culltable_size = 4096;
+static struct object **cullbuild;
+static struct object **cullready;
static int oldest_build = -1;
static int oldest_ready = -1;
@@ -97,11 +98,13 @@ static int ncullable = 0;
static const char *configfile = "/etc/cachefilesd.conf";
+static const char *devfile = "/dev/cachefiles";
static const char *procfile = "/proc/fs/cachefiles";
+static const char *pidfile = "/var/run/cachefilesd.pid";
static char *cacheroot, *graveyardpath;
static int xdebug, xnolog, xopenedlog;
-static int stop, reap, cull, statecheck;
+static int stop, reap, cull; //, statecheck;
static int graveyardfd;
static unsigned long long brun, bcull, bstop, frun, fcull, fstop;
@@ -112,12 +115,13 @@ static void help(void)
{
fprintf(stderr,
"Format:\n"
- " /sbin/cachefilesd [-d]* [-s] [-n] [-f <configfile>]\n"
+ " /sbin/cachefilesd [-d]* [-s] [-n] [-p <pidfile>] [-f <configfile>]\n"
"\n"
"Options:\n"
" -d\tIncrease debugging level (cumulative)\n"
" -n\tDon't daemonise the process\n"
" -s\tMessage output to stderr instead of syslog\n"
+ " -p <pidfile>\tWrite the PID into the file\n"
" -f <configfile>\n"
"\tRead the specified configuration file instead of"
" /etc/cachefiles.conf\n");
@@ -191,12 +195,13 @@ static void cachefilesd(void) __attribute__((noreturn));
static void reap_graveyard(void);
static void reap_graveyard_aux(const char *dirname);
static void read_cache_state(void);
+static int is_object_in_use(int dirfd, const char *filename);
static void cull_file(int dirfd, const char *filename);
static void build_cull_table(void);
static void decant_cull_table(void);
static void insert_into_cull_table(struct object *object);
static void put_object(struct object *object);
-static struct object *create_object(struct object *parent, const char *name, struct stat *st);
+static struct object *create_object(struct object *parent, const char *name, struct stat64 *st);
static void destroy_unexpected_object(struct object *parent, struct dirent *de);
static int get_dir_fd(struct object *dir);
static void cull_object(struct object *object);
@@ -224,23 +229,31 @@ static void sigio(int sig)
/*****************************************************************************/
/*
- * the CacheFiles module signalled a significant change of state
+ * redo scan after a time since the last scan turned up no results
*/
-static void sigurg(int sig)
+static void sigalrm(int sig)
{
- statecheck = 1;
+ jumpstart_scan = 1;
-} /* end sigurg() */
+} /* end sigalrm() */
/*****************************************************************************/
/*
- * redo scan after a time since the last scan turned up no results
+ * write the PID file
*/
-static void sigalrm(int sig)
+static void write_pidfile(void)
{
- jumpstart_scan = 1;
+ FILE *pf;
-} /* end sigalrm() */
+ pf = fopen(pidfile, "w");
+ if (!pf)
+ oserror("Unable to open PID file: %s", pidfile);
+
+ if (fprintf(pf, "%d\n", getpid()) < 0 ||
+ fclose(pf) == EOF)
+ oserror("Unable to write PID file: %s", pidfile);
+
+} /* end write_pidfile() */
/*****************************************************************************/
/*
@@ -262,7 +275,7 @@ int main(int argc, char *argv[])
help();
/* parse the arguments */
- while (opt = getopt(argc, argv, "dsnf:"),
+ while (opt = getopt(argc, argv, "dsnf:p:"),
opt != EOF
) {
switch (opt) {
@@ -286,6 +299,11 @@ int main(int argc, char *argv[])
configfile = optarg;
break;
+ case 'p':
+ /* use a specific PID file */
+ pidfile = optarg;
+ break;
+
default:
opterror("Unknown commandline option '%c'", optopt);
}
@@ -310,10 +328,20 @@ int main(int argc, char *argv[])
/* just in case... */
sync();
- /* open the procfile on fd 3 */
- _cachefd = open(procfile, O_RDWR);
- if (_cachefd < 0)
- oserror("Unable to open %s", procfile);
+ /* open the devfile or the procfile on fd 3 */
+ _cachefd = open(devfile, O_RDWR);
+ if (_cachefd < 0) {
+ if (errno != ENOENT)
+ oserror("Unable to open %s", devfile);
+
+ _cachefd = open(procfile, O_RDWR);
+ if (_cachefd < 0) {
+ if (errno == ENOENT)
+ oserror("Unable to open %s", devfile);
+ oserror("Unable to open %s", procfile);
+ }
+ }
+
if (_cachefd != cachefd) {
if (dup2(_cachefd, cachefd) < 0)
oserror("Unable to transfer cache fd to 3");
@@ -364,18 +392,34 @@ int main(int argc, char *argv[])
if (*cp == '#')
continue;
+ /* note the cull table size command */
+ if (memcmp(cp, "culltable", 9) == 0 && isspace(cp[9])) {
+ unsigned long cts;
+ char *sp;
+
+ for (sp = cp + 10; isspace(*sp); sp++) {;}
+
+ cts = strtoul(sp, &sp, 10);
+ if (*sp)
+ cfgerror("Invalid cull table size number");
+ if (cts < 12 || cts > 20)
+ cfgerror("Log2 of cull table size must be 12 <= N <= 20");
+ culltable_size = 1 << cts;
+ continue;
+ }
+
/* note the dir command */
if (memcmp(cp, "dir", 3) == 0 && isspace(cp[3])) {
char *sp;
for (sp = cp + 4; isspace(*sp); sp++) {;}
- if (stat(sp, &st) < 0)
- oserror("Can't confirm cache location");
-
if (strlen(sp) > PATH_MAX - 10)
cfgerror("Cache pathname is too long");
+ if (stat(sp, &st) < 0)
+ oserror("Can't confirm cache location");
+
cacheroot = strdup(sp);
if (!cacheroot)
oserror("Can't copy cache name");
@@ -403,6 +447,15 @@ int main(int argc, char *argv[])
if (fclose(config) == EOF)
oserror("Unable to close %s", configfile);
+ /* allocate the cull tables */
+ cullbuild = calloc(culltable_size, sizeof(cullbuild[0]));
+ if (!cullbuild)
+ oserror("calloc");
+
+ cullready = calloc(culltable_size, sizeof(cullready[0]));
+ if (!cullready)
+ oserror("calloc");
+
/* leave stdin, stdout, stderr and cachefd open only */
if (nullfd != 0)
dup2(nullfd, 0);
@@ -441,6 +494,7 @@ int main(int argc, char *argv[])
signal(SIGTTOU, SIG_IGN);
signal(SIGTSTP, SIG_IGN);
setsid();
+ write_pidfile();
cachefilesd();
default:
@@ -499,14 +553,14 @@ static void cachefilesd(void)
{
sigset_t sigs, osigs;
- notice("Daemon Started");
-
- /* the cache handle should generate SIGURG */
- if (fcntl(cachefd, F_SETSIG, SIGURG) < 0)
- oserror("Unable to set cache handle to generate SIGURG");
+ struct pollfd pollfds[1] = {
+ [0] = {
+ .fd = cachefd,
+ .events = POLLIN,
+ },
+ };
- if (fcntl(cachefd, F_SETOWN, getpid()) < 0)
- oserror("Unable to set cache handle to deliver SIGURG here");
+ notice("Daemon Started");
/* open the cache directories */
open_cache();
@@ -516,13 +570,11 @@ static void cachefilesd(void)
*/
sigemptyset(&sigs);
sigaddset(&sigs, SIGIO);
- sigaddset(&sigs, SIGURG);
sigaddset(&sigs, SIGINT);
sigaddset(&sigs, SIGTERM);
signal(SIGTERM, sigterm);
signal(SIGINT, sigterm);
- signal(SIGURG, sigurg);
/* check the graveyard for graves */
reap_graveyard();
@@ -537,8 +589,8 @@ static void cachefilesd(void)
oserror("Unable to block signals");
if (!reap && !cull) {
- sigsuspend(&osigs);
- if (errno != EINTR)
+ if (ppoll(pollfds, 1, NULL, &osigs) < 0 &&
+ errno != EINTR)
oserror("Unable to suspend process");
}
@@ -709,6 +761,26 @@ static void read_cache_state(void)
/*****************************************************************************/
/*
+ * find out if an object is in use
+ */
+static int is_object_in_use(int dirfd, const char *filename)
+{
+ char buffer[NAME_MAX + 30];
+ int ret, n;
+
+ n = sprintf(buffer, "inuse %d %s", dirfd, filename);
+
+ /* command the module */
+ ret = write(cachefd, buffer, n);
+ if (ret < 0 && errno != ESTALE && errno != ENOENT && errno != EBUSY)
+ oserror("Failed to check object's in-use state");
+
+ return ret < 0 && errno == EBUSY ? 1 : 0;
+
+} /* end is_object_in_use */
+
+/*****************************************************************************/
+/*
* cull a file representing an object
* - requests CacheFiles rename the object "<dirfd>/filename" to the graveyard
*/
@@ -733,7 +805,7 @@ static void cull_file(int dirfd, const char *filename)
*/
static struct object *create_object(struct object *parent,
const char *name,
- struct stat *st)
+ struct stat64 *st)
{
struct object *object, *p, *pr;
int len;
@@ -904,7 +976,7 @@ static void insert_into_cull_table(struct object *object)
}
/* insert somewhere if table is not full */
- if (oldest_build < CULLTABLE_SIZE - 1) {
+ if (oldest_build < culltable_size - 1) {
object->usage++;
oldest_build++;
@@ -957,7 +1029,7 @@ static void insert_into_cull_table(struct object *object)
}
/* if table is full then insert only if older than newest */
- if (oldest_build > CULLTABLE_SIZE - 1)
+ if (oldest_build > culltable_size - 1)
error("Cull table overfull");
if (object->atime >= cullbuild[0]->atime)
@@ -975,12 +1047,12 @@ static void insert_into_cull_table(struct object *object)
}
/* shift everything up one if older than oldest */
- if (object->atime <= cullbuild[CULLTABLE_SIZE - 1]->atime) {
+ if (object->atime <= cullbuild[culltable_size - 1]->atime) {
memmove(&cullbuild[0],
&cullbuild[1],
- (CULLTABLE_SIZE - 1) * sizeof(cullbuild[0]));
+ (culltable_size - 1) * sizeof(cullbuild[0]));
- cullbuild[CULLTABLE_SIZE - 1] = object;
+ cullbuild[culltable_size - 1] = object;
return;
}
@@ -991,7 +1063,7 @@ static void insert_into_cull_table(struct object *object)
cullbuild[0] = cullbuild[1];
y = 2;
- o = CULLTABLE_SIZE - 1;
+ o = culltable_size - 1;
do {
m = (y + o) / 2;
@@ -1024,7 +1096,7 @@ static void build_cull_table(void)
{
struct dirent dirent, *de;
struct object *curr, *child;
- struct stat st;
+ struct stat64 st;
int loop, fd;
curr = scan;
@@ -1083,7 +1155,7 @@ next:
goto found_unexpected_object;
/* see if this object is already known to us */
- if (fstatat(dirfd(curr->dir), dirent.d_name, &st, 0) < 0) {
+ if (fstatat64(dirfd(curr->dir), dirent.d_name, &st, 0) < 0) {
if (errno == ENOENT)
goto next;
oserror("Failed to stat directory");
@@ -1163,9 +1235,12 @@ next:
;
}
- debug(2, "- insert");
- child->new = 0;
- insert_into_cull_table(child);
+ /* add objects that aren't in use to the cull table */
+ if (!is_object_in_use(dirfd(curr->dir), dirent.d_name)) {
+ debug(2, "- insert");
+ child->new = 0;
+ insert_into_cull_table(child);
+ }
put_object(child);
goto next;
@@ -1279,7 +1354,7 @@ static void decant_cull_table(void)
}
/* decant some of the build table if there's space */
- space = CULLTABLE_SIZE - (oldest_ready + 1);
+ space = culltable_size - (oldest_ready + 1);
if (space <= 0) {
if (space < 0)
error("Less than zero space in ready table");
@@ -1305,7 +1380,7 @@ static void decant_cull_table(void)
memset(&cullbuild[leave], 0x6b, copy * sizeof(cullbuild[0]));
oldest_build = leave - 1;
- if (copy + leave > CULLTABLE_SIZE)
+ if (copy + leave > culltable_size)
error("Scan table exceeded (%d+%d)", copy, leave);
check:
@@ -1352,14 +1427,14 @@ static int get_dir_fd(struct object *dir)
*/
static void cull_object(struct object *object)
{
- struct stat st;
+ struct stat64 st;
int dirfd;
debug(1, "CULL %s", object->name);
dirfd = get_dir_fd(object->parent);
if (dirfd >= 0) {
- if (fstatat(dirfd, object->name, &st, 0) < 0) {
+ if (fstatat64(dirfd, object->name, &st, 0) < 0) {
if (errno != ENOENT)
oserror("Failed to re-stat object");
@@ -1394,7 +1469,7 @@ static void cull_objects(void)
}
/* must start refilling the cull table */
- if (!scan && oldest_build <= CULLTABLE_SIZE / 2 + 2) {
+ if (!scan && oldest_build <= culltable_size / 2 + 2) {
decant_cull_table();
notice("Refilling cull table");
diff --git a/cachefilesd.conf.5 b/cachefilesd.conf.5
index f3681ae..f3b8933 100644
--- a/cachefilesd.conf.5
+++ b/cachefilesd.conf.5
@@ -7,7 +7,7 @@
.\" as published by the Free Software Foundation; either version
.\" 2 of the License, or (at your option) any later version.
.\"
-.TH CACHEFILESD.CONF 5 "11 July 2005" Linux "Cache Files Utilities"
+.TH CACHEFILESD.CONF 5 "14 November 2005" Linux "Cache Files Utilities"
.SH NAME
/etc/cachefilesd.conf \- Local file caching configuration file
.SH SYNOPSIS
@@ -24,7 +24,8 @@ considered to be comments and are discarded.
The only mandatory command is:
.TP
.B dir <path>
-This command specifies the directory containing the root of the cache.
+This command specifies the directory containing the root of the cache. It may
+only specified once per configuration file.
.P
All the other commands are optional:
.TP
@@ -51,6 +52,17 @@ This command specifies a tag to FS-Cache to use in distinguishing multiple
caches. This is only required if more than one cache is going to be used. The
default is "CacheFiles".
.TP
+.B culltable <log2size>
+This command specifies the size of the tables holding the lists of cullable
+objects in the cache. The bigger the number, the faster and more smoothly that
+culling can proceed when there are many objects in the cache, but the more
+memory will be consumed by cachefilesd.
+.IP
+The quantity is specified as log2 of the size actually required, for example 12
+indicates a table of 4096 entries and 13 indicates 8192 entries. The
+permissible values are between 12 and 20, the latter indicating 1048576
+entries. The default is 12.
+.TP
.B debug <mask>
This command specifies a numeric bitmask to control debugging in the kernel
module. The default is zero (all off). The following values can be OR'd into
@@ -67,7 +79,7 @@ Turn on trace of function exit (_leave() macros)
Turn on trace of internal debug points (_debug())
.RE
.IP
-This mask can also be set through /proc/sys/fs/cachefiles/debug.
+This mask can also be set through /sys/module/cachefiles/parameters/debug.
.RE
.SH EXAMPLES
.P
@@ -135,7 +147,7 @@ These are then culled in least recently used order. A new scan of the cache is
started as soon as space is made in the table. Objects will be skipped if
their atimes have changed or if the kernel module says it is still using them.
.SH SEE ALSO
-\fBcachefilesd\fR(8), \fBdf\fR(1), /usr/share/docs/cachefilesd-*/README
+\fBcachefilesd\fR(8), \fBdf\fR(1), /usr/share/doc/cachefilesd-*/README
.SH AUTHORS
The cachefilesd software has been developed by David Howells
.Aq dhowells@redhat.com .
diff --git a/cachefilesd.initd b/cachefilesd.initd
index b6d0f5f..06c4237 100755
--- a/cachefilesd.initd
+++ b/cachefilesd.initd
@@ -22,6 +22,7 @@ fi
OPTIONS=""
RETVAL=0
LOCKFILE=/var/lock/subsys/cachefilesd
+PIDFILE=/var/run/cachefilesd.pid
MODPROBE=/sbin/modprobe
MODPROBE_ARGS=""
PROG="cachefilesd"
@@ -31,7 +32,7 @@ PROG="cachefilesd"
# Check for and source configuration file otherwise set defaults
[ -f /etc/sysconfig/$PROG ] && . /etc/sysconfig/$PROG
-case "$1" in
+case "$1" in
start|condstart)
# Make sure the daemon is not already running.
if status $PROG > /dev/null ; then
@@ -41,7 +42,7 @@ case "$1" in
echo -n $"Starting $PROG: "
- # Load the cachefiles module if needed
+ # Load the cachefiles module if needed
[ -x "$MODPROBE" ] && {
if ! /sbin/lsmod | grep cachefiles > /dev/null ; then
$MODPROBE cachefiles $MODPROBE_ARGS || exit 1
@@ -49,15 +50,15 @@ case "$1" in
}
# Start daemon.
- daemon $PROG ${OPTIONS}
+ daemon --pidfile=$PIDFILE $PROG ${OPTIONS}
RETVAL=$?
echo
[ $RETVAL -eq 0 ] && touch $LOCKFILE
;;
stop)
# Stop daemon.
- echo -n $"Shutting down RPC $PROG: "
- killproc $PROG
+ echo -n $"Shutting down $PROG: "
+ killproc -p $PIDFILE
RETVAL=$?
echo
[ $RETVAL -eq 0 ] && rm -f $LOCKFILE
diff --git a/howto.txt b/howto.txt
index d444386..1114ea2 100644
--- a/howto.txt
+++ b/howto.txt
@@ -14,6 +14,8 @@ CONTENTS
(*) Monitoring.
+ (*) Relocating the cache.
+
(*) Further information.
@@ -252,6 +254,21 @@ The "FSC" column says "yes" when the system has been asked to cache a
particular NFS share/volume/export, and "no" when it hasn't.
+====================
+RELOCATING THE CACHE
+====================
+
+By default, the cache is located in /var/fscache, but this may be undesirable.
+Unless SELinux is being used in enforcing mode, relocating the cache is
+trivially a matter of changing the "dir" line in /etc/cachefilesd.
+
+However, if SELinux is being used in enforcing mode, then it's not that
+simple. The security policy that governs access to the cache must be changed.
+For more information, see:
+
+ move-cache.txt
+
+
===================
FURTHER INFORMATION
===================
diff --git a/redhat/cachefilesd.spec b/redhat/cachefilesd.spec
index 5754a24..16f567e 100644
--- a/redhat/cachefilesd.spec
+++ b/redhat/cachefilesd.spec
@@ -1,24 +1,46 @@
+%define selinux_variants mls strict targeted
+%define selinux_policyver %(sed -e 's,.*selinux-policy-\\([^/]*\\)/.*,\\1,' /usr/share/selinux/devel/policyhelp)
+
Name: cachefilesd
-Version: 0.7
-Release: 1%{?dist}
+Version: 0.8
+Release: 16%{?dist}
Summary: CacheFiles userspace management daemon
Group: System Environment/Daemons
License: GPL
-URL: http://people.redhat.com/~dhowells/fscache/
-Source0: http://people.redhat.com/dhowells/fscache/cachefilesd-0.6.tar.bz2
+URL: http://people.redhat.com/~dhowells/fscache/
+Source0: http://people.redhat.com/dhowells/fscache/cachefilesd-%{version}.tar.bz2
+Source1: cachefilesd.if
+Source2: cachefilesd.te
+Source3: cachefilesd.fc
BuildRoot: %{_tmppath}/%{name}-%{version}-root-%(%{__id_u} -n)
BuildRequires: automake, autoconf
Requires(post): /sbin/chkconfig, /sbin/service
Requires(preun): /sbin/chkconfig, /sbin/service
+Requires: %{name}-selinux = %{version}-%{release}
%description
The cachefilesd daemon manages the caching files and directory that are
that are used by network filesystems such a AFS and NFS to
do persistent caching to the local disk.
+%package selinux
+Summary: SELinux policy module supporting cachefilesd
+Group: System Environment/Base
+BuildRequires: checkpolicy, selinux-policy-devel, hardlink
+%if "%{selinux_policyver}" != ""
+Requires: selinux-policy >= %{selinux_policyver}
+%endif
+Requires(post): /usr/sbin/semodule, /sbin/restorecon
+Requires(postun): /usr/sbin/semodule, /sbin/restorecon
+
+%description selinux
+SELinux policy module supporting cachefilesd
+
%prep
%setup -q
+mkdir SELinux
+cp -p %{SOURCE1} %{SOURCE2} %{SOURCE3} SELinux
%build
%ifarch s390 s390x
@@ -31,23 +53,59 @@ CFLAGS="`echo $RPM_OPT_FLAGS $ARCH_OPT_FLAGS $PIE`"
make all
+# Build SELinux policy modules
+cd SELinux
+for selinuxvariant in %{selinux_variants}
+do
+ make NAME=${selinuxvariant} -f /usr/share/selinux/devel/Makefile
+ mv cachefilesd.pp cachefilesd.pp.${selinuxvariant}
+ make NAME=${selinuxvariant} -f /usr/share/selinux/devel/Makefile clean
+done
+cd -
%install
rm -rf %{buildroot}
mkdir -p %{buildroot}/sbin
mkdir -p %{buildroot}%{_sysconfdir}/rc.d/init.d
mkdir -p %{buildroot}%{_mandir}/{man5,man8}
+mkdir -p %{buildroot}/usr/share/doc/%{name}-%{version}
+mkdir -p %{buildroot}%{_localstatedir}/fscache
make DESTDIR=%{buildroot} install
install -m 644 cachefilesd.conf %{buildroot}%{_sysconfdir}
install -m 755 cachefilesd.initd %{buildroot}%{_sysconfdir}/rc.d/init.d/cachefilesd
+# Install SELinux policy modules
+cd SELinux
+for selinuxvariant in %{selinux_variants}
+do
+ install -d %{buildroot}%{_datadir}/selinux/${selinuxvariant}
+ install -p -m 644 cachefilesd.pp.${selinuxvariant} \
+ %{buildroot}%{_datadir}/selinux/${selinuxvariant}/cachefilesd.pp
+done
+cd -
+
+# Hardlink identical policy module packages together
+/usr/sbin/hardlink -cv %{buildroot}%{_datadir}/selinux
+
%clean
rm -rf $RPM_BUILD_ROOT
%post
/sbin/chkconfig --add %{name}
+if [ "$1" -ge 1 ]; then
+ /sbin/service cachefilesd condrestart > /dev/null
+fi
+
+%post selinux
+# Install SELinux policy modules
+for selinuxvariant in %{selinux_variants}
+do
+ /usr/sbin/semodule -s ${selinuxvariant} -i \
+ %{_datadir}/selinux/${selinuxvariant}/cachefilesd.pp &> /dev/null || :
+done
+
%preun
if [ $1 -eq 0 ]; then
/sbin/service cachefilesd stop
@@ -55,23 +113,69 @@ if [ $1 -eq 0 ]; then
fi
%postun
-if [ "$1" -ge 1 ]; then
- /sbin/service cachefilesd condrestart > /dev/null
+if [ $1 -eq 0 ]; then
+ # Fix up non-standard directory context
+ /sbin/restorecon -R %{_localstatedir}/fscache || :
fi
+%postun selinux
+# Clean up after package removal
+if [ $1 -eq 0 ]; then
+ # Remove SELinux policy modules
+ for selinuxvariant in %{selinux_variants}
+ do
+ /usr/sbin/semodule -s ${selinuxvariant} -r cachefilesd &> /dev/null || :
+ done
+ # Clean up any remaining file contexts (shouldn't be any really)
+ [ -d %{_localstatedir}/fscache ] && \
+ /sbin/restorecon -R %{_localstatedir}/fscache &> /dev/null || :
+fi
%files
%defattr(-,root,root)
%doc README
+%doc howto.txt
+%doc move-cache.txt
%config(noreplace) %{_sysconfdir}/cachefilesd.conf
%attr(0755,root,root) %{_sysconfdir}/rc.d/init.d/cachefilesd
/sbin/*
%{_mandir}/*/*
+%{_localstatedir}/fscache
+
+%files selinux
+%defattr(-,root,root,0755)
+%doc SELinux/*
+%{_datadir}/selinux/*/cachefilesd.pp
%changelog
-* Wed Aug 30 2006 David Howells <dhowells@redhat.com> 0.6-1
-- Mark __error() as attribute format printf
-- Fix up format errors shown up
+* Tue Nov 15 2006 David Howells <dhowells@redhat.com> 0.8-15
+- Made cachefilesd ask the kernel whether cullable objects are in use and omit
+ them from the cull table if they are.
+- Made the size of cachefilesd's culling tables configurable.
+- Updated the manual pages.
+
+* Mon Nov 14 2006 David Howells <dhowells@redhat.com> 0.8-14
+- Documented SELinux interaction.
+
+* Fri Nov 10 2006 David Howells <dhowells@redhat.com> 0.8-11
+- Include SELinux policy for cachefilesd.
+
+* Thu Oct 19 2006 Steve Dickson <steved@redhat.com> 0.7-3
+- Fixed typo that was causing the howto.txt not to be installed.
+
+* Tue Oct 17 2006 David Howells <dhowells@redhat.com> 0.8-1
+- Use /dev/cachefiles if it present in preference to /proc/fs/cachefiles.
+- Use poll rather than SIGURG on /dev/cachefilesd.
+
+* Sun Oct 01 2006 Jesse Keating <jkeating@redhat.com> - 0.7-2
+- rebuilt for unwind info generation, broken in gcc-4.1.1-21
+
+* Fri Sep 22 2006 Steve Dickson <steved@redhat.com> 0.7-1
+- updated to 0.7 which adds the howto.txt
+
+* Wed Aug 30 2006 Steve Dickson <steved@redhat.com> 0.6-1
+- Fixed memory corruption problem
+- Added the fcull/fstop/frun options
* Fri Aug 11 2006 Steve Dickson <steved@redhat.com> 0.5-1
- Upgraded to 0.5 which fixed initial scan problem when
diff --git a/selinux/cachefilesd.fc b/selinux/cachefilesd.fc
new file mode 100644
index 0000000..b2db20b
--- /dev/null
+++ b/selinux/cachefilesd.fc
@@ -0,0 +1,28 @@
+###############################################################################
+#
+# Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
+# Written by David Howells (dhowells@redhat.com)
+# Karl MacMillan (kmacmill@redhat.com)
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version
+# 2 of the License, or (at your option) any later version.
+#
+###############################################################################
+
+#
+# Define the contexts to be assigned to various files and directories of
+# importance to the CacheFiles kernel module and userspace management daemon.
+#
+
+# cachefilesd executable will have:
+# label: system_u:object_r:cachefilesd_exec_t
+# MLS sensitivity: s0
+# MCS categories: <none>
+
+/sbin/cachefilesd -- gen_context(system_u:object_r:cachefilesd_exec_t,s0)
+/dev/cachefiles -c gen_context(system_u:object_r:cachefiles_dev_t,s0)
+/var/fscache(/.*)? gen_context(system_u:object_r:cachefiles_var_t,s0)
+
+/var/run/cachefilesd.pid -- gen_context(system_u:object_r:cachefiles_var_t,s0)
diff --git a/selinux/cachefilesd.if b/selinux/cachefilesd.if
new file mode 100644
index 0000000..89d19e0
--- /dev/null
+++ b/selinux/cachefilesd.if
@@ -0,0 +1,41 @@
+###############################################################################
+#
+# Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
+# Written by David Howells (dhowells@redhat.com)
+# Karl MacMillan (kmacmill@redhat.com)
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version
+# 2 of the License, or (at your option) any later version.
+#
+###############################################################################
+
+#
+# Define the policy interface for the CacheFiles userspace management daemon.
+#
+
+## <summary>policy for cachefilesd</summary>
+
+########################################
+## <summary>
+## Execute a domain transition to run cachefilesd.
+## </summary>
+## <param name="domain">
+## <summary>
+## Domain allowed to transition.
+## </summary>
+## </param>
+#
+interface(`cachefilesd_domtrans',`
+ gen_require(`
+ type cachefilesd_t, cachefilesd_exec_t;
+ ')
+
+ domain_auto_trans($1,cachefilesd_exec_t,cachefilesd_t)
+
+ allow $1 cachefilesd_t:fd use;
+ allow cachefilesd_t $1:fd use;
+ allow cachefilesd_t $1:fifo_file rw_file_perms;
+ allow cachefilesd_t $1:process sigchld;
+')
diff --git a/selinux/cachefilesd.te b/selinux/cachefilesd.te
new file mode 100644
index 0000000..b7cff68
--- /dev/null
+++ b/selinux/cachefilesd.te
@@ -0,0 +1,119 @@
+###############################################################################
+#
+# Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
+# Written by David Howells (dhowells@redhat.com)
+# Karl MacMillan (kmacmill@redhat.com)
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version
+# 2 of the License, or (at your option) any later version.
+#
+###############################################################################
+
+#
+# This security policy governs access by the CacheFiles kernel module and
+# userspace management daemon to the files and directories in the on-disk
+# cache, on behalf of the processes accessing the cache through a network
+# filesystem such as NFS
+#
+policy_module(cachefilesd,1.0.16)
+
+###############################################################################
+#
+# Declarations
+#
+###############################################################################
+require { type kernel_t; }
+
+#
+# Files in the cache are created by the cachefiles module with security ID
+# cachefiles_var_t
+#
+type cachefiles_var_t;
+files_type(cachefiles_var_t)
+
+#
+# The /dev/cachefiles character device has security ID cachefiles_dev_t
+#
+type cachefiles_dev_t;
+dev_node(cachefiles_dev_t)
+
+#
+# The cachefilesd daemon normally runs with security ID cachefilesd_t
+#
+type cachefilesd_t;
+type cachefilesd_exec_t;
+domain_type(cachefilesd_t)
+init_daemon_domain(cachefilesd_t, cachefilesd_exec_t)
+
+#
+# The cachefilesd daemon pid file context
+#
+type cachefilesd_var_run_t;
+files_pid_file(cachefilesd_var_run_t)
+
+#
+# The CacheFiles module causes processes accessing the cache files to do so
+# acting as security ID cachefiles_kernel_t
+#
+type cachefiles_kernel_t;
+domain_type(cachefiles_kernel_t)
+domain_obj_id_change_exemption(cachefiles_kernel_t)
+type_transition cachefilesd_t kernel_t : process cachefiles_kernel_t;
+
+###############################################################################
+#
+# Permit RPM to deal with files in the cache
+#
+###############################################################################
+rpm_use_script_fds(cachefilesd_t)
+
+###############################################################################
+#
+# cachefilesd local policy
+#
+# Check in /etc/selinux/refpolicy/include for macros to use instead of allow
+# rules.
+#
+###############################################################################
+allow cachefilesd_t self : capability { setuid setgid sys_admin dac_override };
+
+# Basic access
+files_read_etc_files(cachefilesd_t)
+libs_use_ld_so(cachefilesd_t)
+libs_use_shared_libs(cachefilesd_t)
+miscfiles_read_localization(cachefilesd_t)
+logging_send_syslog_msg(cachefilesd_t)
+init_dontaudit_use_script_ptys(cachefilesd_t)
+term_dontaudit_use_generic_ptys(cachefilesd_t)
+term_dontaudit_getattr_unallocated_ttys(cachefilesd_t)
+
+# Allow manipulation of pid file
+allow cachefilesd_t cachefilesd_var_run_t:file create_file_perms;
+files_pid_filetrans(cachefilesd_t,cachefilesd_var_run_t,file)
+
+# Allow read access to cache
+allow cachefilesd_t cachefiles_var_t : dir create_dir_perms;
+allow cachefilesd_t cachefiles_var_t : file { getattr rename unlink };
+
+# Access to cachefiles device
+allow cachefilesd_t cachefiles_dev_t : chr_file rw_file_perms;
+
+# Permit the filesystem to be statfs'd
+fs_getattr_xattr_fs(cachefilesd_t)
+
+###############################################################################
+#
+# cachefiles kernel module local policy
+#
+###############################################################################
+allow cachefiles_kernel_t self:capability { dac_override dac_read_search };
+allow cachefiles_kernel_t initrc_t:process sigchld;
+
+allow cachefiles_kernel_t cachefiles_var_t : dir manage_dir_perms;
+allow cachefiles_kernel_t cachefiles_var_t : file create_file_perms;
+
+fs_getattr_xattr_fs(cachefiles_kernel_t)
+
+dev_search_sysfs(cachefiles_kernel_t)
diff --git a/selinux/move-cache.txt b/selinux/move-cache.txt
new file mode 100644
index 0000000..8e2f09c
--- /dev/null
+++ b/selinux/move-cache.txt
@@ -0,0 +1,85 @@
+ =====================================================
+ RELOCATING THE CACHE WITH SELINUX ENFORCEMENT ENABLED
+ =====================================================
+
+If the cache is being used on a system on which SELinux is active and running
+in enforcing mode, then the security policy installed by the cachefilesd RPM
+needs to be updated to permit the CacheFiles module and daemon to access the
+cache.
+
+The simplest way to do this is to add an auxiliary policy to mark out the
+location of the new cache, whilst leaving the old location still available for
+caching. If anything more is required, then it will be necessary to modify the
+policy that is installed.
+
+The sources for the installed policy will be themselves installed by the
+cachefilesd-selinux RPM in:
+
+ /usr/share/doc/cachefilesd-selinux-*/
+
+See the files named:
+
+ cachefilesd.te
+ cachefilesd.fc
+ cachefilesd.if
+
+
+==========================
+ADDING AN AUXILIARY POLICY
+==========================
+
+Creating and adding an auxiliary policy is very easy. Follow the following
+steps:
+
+ (0) Check that checkpolicy and selinux-policy-devel packages are installed.
+ These are needed to build your policy.
+
+ (1) Create a new directory and go into it.
+
+ (2) Create a source file to reference the security ID already set up for files
+ in the cache as you'll need these to label your own cache directory.
+ Assuming you're going to name your policy "mycache", this would have to be
+ called "mycache.te":
+
+ [mycache.te]
+ policy_module(mycache,1.0.0)
+ require { type cachefiles_var_t; }
+
+ (3) Create a source file to note the directory in which you wish your cache to
+ reside. This file should be named for your policy, plus a ".fc" suffix:
+
+ [mycache.fc]
+ /mycache(/.*)? gen_context(system_u:object_r:cachefiles_var_t,s0)
+
+ This specifies the security ID for the directory in which your cache will
+ live and all its descendents. Replace "/mycache" with the path to your
+ cache's directory.
+
+ (4) Build the policy:
+
+ make -f /usr/share/selinux/devel/Makefile
+
+ (5) And install it:
+
+ semodule -i mycache.pp
+
+ (6) Create your directory and tell SELinux to label it appropriately:
+
+ mkdir /mycache
+ restorecon /mycache
+
+ (7) Check that the directory is labelled appropriately:
+
+ ls -dZ /mycache
+
+ (8) Modify /etc/cachefilesd.conf to point to the correct directory and then
+ start the cachefilesd service.
+
+The auxiliary policy can be later removed by:
+
+ semodule -r mycache.pp
+
+If the policy is updated, then the version number in policy_module() in
+mycache.te should be increased and the module upgraded:
+
+ semodule -u mycache.pp