New APIs: Implement Linux filesystem capabilities.

This adds the following new APIs:
 - cap_get_file
 - cap_set_file
This commit is contained in:
Richard W.M. Jones
2012-11-22 14:49:54 +00:00
parent 218b39acae
commit fae8d7cafb
8 changed files with 174 additions and 15 deletions

2
README
View File

@@ -110,6 +110,8 @@ For basic functionality and the C tools:
- getfacl, getfattr libraries and programs (optional)
- Linux capabilities library (libcap) (optional)
- netpbm, icoutils (optional)
These programs are used to render icons from guests.

14
TODO
View File

@@ -587,17 +587,3 @@ is very poorly designed and essentially impossible for us to use:
particularly if we also want to maintain backwards compatibility with
Ruby 1.8, and/or maintain volatile VALUEs on the stack.
Filesystem capabilities
-----------------------
We need to model filesystem capabilities through the API. This is
particularly important in order to be able to implement SCAP.
Filesystem capabilities can be read and written using the libcap(3)
library and functions like cap_get_file, cap_set_file.
Setting fs capabilities on a file sets the extended attribute
'security.capability' to a binary blob. These are implemented using a
Linux Security Module (security/capability.c) and presumably by
something in exec, but I couldn't see exactly how this works.

View File

@@ -701,6 +701,15 @@ AC_CHECK_LIB([acl],[acl_from_text],
],
[AC_MSG_WARN([POSIX acl library not found])])
dnl Linux capabilities library (libcap) (highly recommended)
AC_CHECK_LIB([cap],[cap_from_text],
[AC_CHECK_HEADER([sys/capability.h],
[AC_SUBST([CAP_LIBS], [-lcap])
AC_DEFINE([HAVE_CAP], [1], [Define to 1 if the Linux capabilities library (libcap) is available.])
], [])
],
[AC_MSG_WARN([Linux capabilities library (libcap) not found])])
dnl libvirt (highly recommended)
AC_ARG_WITH([libvirt],
[AS_HELP_STRING([--without-libvirt],

View File

@@ -96,6 +96,7 @@ guestfsd_SOURCES = \
blkid.c \
blockdev.c \
btrfs.c \
cap.c \
checksum.c \
cmp.c \
command.c \
@@ -183,6 +184,7 @@ guestfsd_LDADD = \
liberrnostring.a \
libprotocol.a \
$(ACL_LIBS) \
$(CAP_LIBS) \
$(SELINUX_LIB) \
$(AUGEAS_LIBS) \
$(HIVEX_LIBS) \

131
daemon/cap.c Normal file
View File

@@ -0,0 +1,131 @@
/* libguestfs - the guestfsd daemon
* Copyright (C) 2012 Red Hat Inc.
*
* 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 program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <config.h>
#include <stdio.h>
#include <limits.h>
#include <unistd.h>
#include "guestfs_protocol.h"
#include "daemon.h"
#include "actions.h"
#include "optgroups.h"
#if defined(HAVE_CAP)
#include <sys/capability.h>
int
optgroup_linuxcaps_available (void)
{
return 1;
}
char *
do_cap_get_file (const char *path)
{
cap_t cap;
char *r, *ret;
CHROOT_IN;
cap = cap_get_file (path);
CHROOT_OUT;
if (cap == NULL) {
reply_with_perror ("%s", path);
return NULL;
}
r = cap_to_text (cap, NULL);
if (r == NULL) {
reply_with_perror ("cap_to_text");
cap_free (cap);
return NULL;
}
cap_free (cap);
/* 'r' is not an ordinary pointer that can be freed with free(3)!
* In the current implementation of libcap, if you try to do that it
* will segfault. We have to duplicate this into an ordinary
* buffer, then call cap_free (r).
*/
ret = strdup (r);
if (ret == NULL) {
reply_with_perror ("strdup");
cap_free (r);
return NULL;
}
cap_free (r);
return ret; /* caller frees */
}
int
do_cap_set_file (const char *path, const char *capstr)
{
cap_t cap;
int r;
cap = cap_from_text (capstr);
if (cap == NULL) {
reply_with_perror ("could not parse cap string: %s: cap_from_text", capstr);
return -1;
}
CHROOT_IN;
r = cap_set_file (path, cap);
CHROOT_OUT;
if (r == -1) {
reply_with_perror ("%s", path);
cap_free (cap);
return -1;
}
cap_free (cap);
return 0;
}
#else /* no libcap */
/* Note that the wrapper code (daemon/stubs.c) ensures that the
* functions below are never called because
* optgroup_linuxcaps_available returns false.
*/
int
optgroup_linuxcaps_available (void)
{
return 0;
}
char *
do_cap_get_file (const char *path)
{
abort ();
}
int
do_cap_set_file (const char *path, const char *cap)
{
abort ();
}
#endif /* no libcap */

View File

@@ -10490,6 +10490,34 @@ C<path> is a directory.
This function deletes the default POSIX Access Control List (ACL)
attached to directory C<dir>." };
{ defaults with
name = "cap_get_file";
style = RString "cap", [Pathname "path"], [];
proc_nr = Some 378;
optional = Some "linuxcaps";
tests = []; (* tested by cap_set_file *)
shortdesc = "get the Linux capabilities attached to a file";
longdesc = "\
This function returns the Linux capabilities attached to C<path>.
The capabilities set is returned in text form (see L<cap_to_text(3)>)." };
{ defaults with
name = "cap_set_file";
style = RErr, [Pathname "path"; String "cap"], [];
proc_nr = Some 379;
optional = Some "linuxcaps";
tests = [
InitScratchFS, Always, TestOutput (
[["touch"; "/cap_set_file_0"];
["cap_set_file"; "/cap_set_file_0"; "cap_chown=p cap_chown+e"];
["cap_get_file"; "/cap_set_file_0"]], "= cap_chown+ep");
];
shortdesc = "set the Linux capabilities attached to a file";
longdesc = "\
This function sets the Linux capabilities attached to C<path>.
The capabilities set C<cap> should be passed in text form
(see L<cap_from_text(3)>)." };
]
(* Non-API meta-commands available only in guestfish.

View File

@@ -11,6 +11,7 @@ daemon/base64.c
daemon/blkid.c
daemon/blockdev.c
daemon/btrfs.c
daemon/cap.c
daemon/checksum.c
daemon/cmp.c
daemon/command.c

View File

@@ -1 +1 @@
377
379