2
0
mirror of https://gitlab.com/apparmor/apparmor synced 2025-08-31 14:25:52 +00:00

parser: Shove binary file and fd reading into kernel_interface.c

This is the start of the kernel_interface API that allows callers to
specify a buffer, a file path, or a file descriptor that should be
copied to the proper kernel interface for loading, replacing, or
removing in-kernel policies.

Support exists for reading from a file path or file descriptor into a
buffer and then writing that buffer to the appropriate apparmorfs
interface file.

An aa_kernel_interface_write_policy() function is also provided for
callers that want to route a buffer to an arbitrary file descriptor
instead of to an apparmorfs file. This is useful when an admin instructs
apparmor_parser to write to stdout or a file.

Additionally, it removes some parser-specific globals from the
kernel_interface.c file, such as OPTION_{ADD,REPLACE,REMOVE}, in
preparation for moving the code into a library.

Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
Acked-by: John Johansen <john.johansen@canonical.com>
This commit is contained in:
Tyler Hicks
2015-03-25 17:09:26 -05:00
parent 8553727414
commit a23b6a1f81
4 changed files with 173 additions and 104 deletions

View File

@@ -88,15 +88,12 @@ static const char *next_profile_buffer(const char *buffer, int size)
return NULL;
}
static int write_buffer(int fd, const char *buffer, int size, int set)
static int write_buffer(int fd, const char *buffer, int size)
{
const char *err_str = set ? "profile set" : "profile";
int wsize = write(fd, buffer, size);
if (wsize < 0) {
PERROR(_("%s: Unable to write %s\n"), progname, err_str);
return -1;
} else if (wsize < size) {
PERROR(_("%s: Unable to write %s\n"), progname, err_str);
errno = EPROTO;
return -1;
}
@@ -124,7 +121,7 @@ static int write_policy_buffer(int fd, int atomic,
int rc;
if (atomic) {
rc = write_buffer(fd, buffer, size, true);
rc = write_buffer(fd, buffer, size);
} else {
const char *b, *next;
@@ -136,7 +133,7 @@ static int write_policy_buffer(int fd, int atomic,
bsize = next - b;
else
bsize = size;
if (write_buffer(fd, b, bsize, false) == -1)
if (write_buffer(fd, b, bsize) == -1)
return -1;
}
}
@@ -147,83 +144,156 @@ static int write_policy_buffer(int fd, int atomic,
return 0;
}
/**
* open_option_iface - open the interface file for @option
* @aadir: apparmorfs dir
* @option: load command option
*
* Returns: fd to interface or -1 on error, with errno set.
*/
static int open_option_iface(int aadir, int option)
{
const char *name;
#define AA_IFACE_FILE_LOAD ".load"
#define AA_IFACE_FILE_REMOVE ".remove"
#define AA_IFACE_FILE_REPLACE ".replace"
switch (option) {
case OPTION_ADD:
name = ".load";
break;
case OPTION_REPLACE:
name = ".replace";
break;
case OPTION_REMOVE:
name = ".remove";
break;
default:
errno = EINVAL;
return -1;
}
return openat(aadir, name, O_WRONLY);
/* TODO: push up */
/*
if (fd < 0) {
PERROR(_("Unable to open %s - %s\n"), filename,
strerror(errno));
return -errno;
}
*/
}
int aa_load_buffer(int option, char *buffer, int size)
static int write_policy_buffer_to_iface(const char *iface_file,
const char *buffer, size_t size)
{
autoclose int dirfd = -1;
autoclose int fd = -1;
/* TODO: push backup into caller */
if (!kernel_load)
return 0;
dirfd = open_iface_dir();
if (dirfd == -1)
return -1;
fd = open_option_iface(dirfd, option);
fd = openat(dirfd, iface_file, O_WRONLY | O_CLOEXEC);
if (fd == -1)
return -1;
return write_policy_buffer(fd, kernel_supports_setload, buffer, size);
}
/**
* aa_remove_profile - remove a profile from the kernel
* @fqname: the fully qualified name of the profile to remove
*
* Returns: 0 on success, -1 on error with errno set
*/
int aa_remove_profile(const char *fqname)
static int write_policy_fd_to_iface(const char *iface_file, int fd)
{
autoclose int dirfd = -1;
autoclose int fd = -1;
autofree char *buffer = NULL;
int size = 0, asize = 0, rsize;
int chunksize = 1 << 14;
dirfd = open_iface_dir();
if (dirfd == -1)
do {
if (asize - size == 0) {
buffer = (char *) realloc(buffer, chunksize);
asize = chunksize;
chunksize <<= 1;
if (!buffer) {
errno = ENOMEM;
return -1;
}
}
rsize = read(fd, buffer + size, asize - size);
if (rsize)
size += rsize;
} while (rsize > 0);
if (rsize == -1)
return -1;
fd = open_option_iface(dirfd, OPTION_REMOVE);
return write_policy_buffer_to_iface(iface_file, buffer, size);
}
static int write_policy_file_to_iface(const char *iface_file, const char *path)
{
autoclose int fd;
fd = open(path, O_RDONLY);
if (fd == -1)
return -1;
/* include trailing \0 in buffer write */
return write_buffer(fd, fqname, strlen(fqname) + 1, 0);
return write_policy_fd_to_iface(iface_file, fd);
}
/**
* aa_kernel_interface_load_policy - load a policy into the kernel
* @buffer: a buffer containing a policy
* @size: the size of the buffer
*
* Returns: 0 on success, -1 on error with errno set
*/
int aa_kernel_interface_load_policy(const char *buffer, size_t size)
{
return write_policy_buffer_to_iface(AA_IFACE_FILE_LOAD, buffer, size);
}
/**
* aa_kernel_interface_load_policy_from_file - load a policy into the kernel
* @path: path to a policy binary
*
* Returns: 0 on success, -1 on error with errno set
*/
int aa_kernel_interface_load_policy_from_file(const char *path)
{
return write_policy_file_to_iface(AA_IFACE_FILE_LOAD, path);
}
/**
* aa_kernel_interface_load_policy_from_fd - load a policy into the kernel
* @fd: a pre-opened, readable file descriptor at the correct offset
*
* Returns: 0 on success, -1 on error with errno set
*/
int aa_kernel_interface_load_policy_from_fd(int fd)
{
return write_policy_fd_to_iface(AA_IFACE_FILE_LOAD, fd);
}
/**
* aa_kernel_interface_replace_policy - replace a policy in the kernel
* @buffer: a buffer containing a policy
* @size: the size of the buffer
*
* Returns: 0 on success, -1 on error with errno set
*/
int aa_kernel_interface_replace_policy(const char *buffer, size_t size)
{
return write_policy_buffer_to_iface(AA_IFACE_FILE_REPLACE,
buffer, size);
}
/**
* aa_kernel_interface_replace_policy_from_file - replace a policy in the kernel
* @path: path to a policy binary
*
* Returns: 0 on success, -1 on error with errno set
*/
int aa_kernel_interface_replace_policy_from_file(const char *path)
{
return write_policy_file_to_iface(AA_IFACE_FILE_REPLACE, path);
}
/**
* aa_kernel_interface_replace_policy_from_fd - replace a policy in the kernel
* @fd: a pre-opened, readable file descriptor at the correct offset
*
* Returns: 0 on success, -1 on error with errno set
*/
int aa_kernel_interface_replace_policy_from_fd(int fd)
{
return write_policy_fd_to_iface(AA_IFACE_FILE_REPLACE, fd);
}
/**
* aa_kernel_interface_remove_policy - remove a policy from the kernel
* @fqname: nul-terminated fully qualified name of the policy to remove
*
* Returns: 0 on success, -1 on error with errno set
*/
int aa_kernel_interface_remove_policy(const char *fqname)
{
return write_policy_buffer_to_iface(AA_IFACE_FILE_REMOVE,
fqname, strlen(fqname) + 1);
}
/**
* aa_kernel_interface_write_policy - write a policy to a file descriptor
* @fd: a pre-opened, writeable file descriptor at the correct offset
* @buffer: a buffer containing a policy
* @size: the size of the buffer
*
* Returns: 0 on success, -1 on error with errno set
*/
int aa_kernel_interface_write_policy(int fd, const char *buffer, size_t size)
{
return write_policy_buffer(fd, 1, buffer, size);
}

View File

@@ -20,7 +20,13 @@
#define __AA_KERNEL_INTERFACE_H
int aa_find_iface_dir(char **dir);
int aa_load_buffer(int option, char *buffer, int size);
int aa_remove_profile(const char *fqname);
int aa_kernel_interface_load_policy(const char *buffer, size_t size);
int aa_kernel_interface_load_policy_from_file(const char *path);
int aa_kernel_interface_load_policy_from_fd(int fd);
int aa_kernel_interface_replace_policy(const char *buffer, size_t size);
int aa_kernel_interface_replace_policy_from_file(const char *path);
int aa_kernel_interface_replace_policy_from_fd(int fd);
int aa_kernel_interface_remove_policy(const char *fqname);
int aa_kernel_interface_write_policy(int fd, const char *buffer, size_t size);
#endif /* __AA_KERNEL_INTERFACE_H */

View File

@@ -522,7 +522,7 @@ int __sd_serialize_profile(int option, Profile *prof, int cache_fd)
if (option == OPTION_REMOVE) {
if (kernel_load) {
if (aa_remove_profile(prof->fqname().c_str()) == -1)
if (aa_kernel_interface_remove_policy(prof->fqname().c_str()) == -1)
error = -errno;
}
} else {

View File

@@ -605,62 +605,55 @@ static void set_supported_features(void)
int process_binary(int option, const char *profilename)
{
autofree char *buffer = NULL;
int retval = 0, size = 0, asize = 0, rsize;
int chunksize = 1 << 14;
autoclose int fd = -1;
const char *printed_name;
int retval;
if (profilename) {
fd = open(profilename, O_RDONLY);
if (fd == -1) {
retval = errno;
PERROR(_("Error: Could not read binary profile or cache file %s: %s.\n"),
profilename, strerror(errno));
return retval;
}
} else {
fd = dup(0);
}
printed_name = profilename ? profilename : "stdin";
do {
if (asize - size == 0) {
buffer = (char *) realloc(buffer, chunksize);
asize = chunksize;
chunksize <<= 1;
if (!buffer) {
PERROR(_("Memory allocation error."));
return ENOMEM;
if (kernel_load) {
if (option == OPTION_ADD) {
retval = profilename ?
aa_kernel_interface_load_policy_from_file(profilename) :
aa_kernel_interface_load_policy_from_fd(0);
if (retval == -1) {
retval = errno;
PERROR(_("Error: Could not load profile %s: %s\n"),
printed_name, strerror(retval));
return retval;
}
} else if (option == OPTION_REPLACE) {
retval = profilename ?
aa_kernel_interface_replace_policy_from_file(profilename) :
aa_kernel_interface_replace_policy_from_fd(0);
if (retval == -1) {
retval = errno;
PERROR(_("Error: Could not replace profile %s: %s\n"),
printed_name, strerror(retval));
return retval;
}
} else {
PERROR(_("Error: Invalid load option specified: %d\n"),
option);
return EINVAL;
}
rsize = read(fd, buffer + size, asize - size);
if (rsize)
size += rsize;
} while (rsize > 0);
if (rsize == 0) {
retval = aa_load_buffer(option, buffer, size);
if (retval == -1)
retval = -errno;
} else
retval = rsize;
}
if (conf_verbose) {
switch (option) {
case OPTION_ADD:
printf(_("Cached load succeeded for \"%s\".\n"),
profilename ? profilename : "stdin");
printed_name);
break;
case OPTION_REPLACE:
printf(_("Cached reload succeeded for \"%s\".\n"),
profilename ? profilename : "stdin");
printed_name);
break;
default:
break;
}
}
return retval;
return 0;
}
void reset_parser(const char *filename)