mirror of
https://gitlab.com/apparmor/apparmor
synced 2025-09-02 23:35:37 +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:
@@ -88,15 +88,12 @@ static const char *next_profile_buffer(const char *buffer, int size)
|
|||||||
return NULL;
|
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);
|
int wsize = write(fd, buffer, size);
|
||||||
if (wsize < 0) {
|
if (wsize < 0) {
|
||||||
PERROR(_("%s: Unable to write %s\n"), progname, err_str);
|
|
||||||
return -1;
|
return -1;
|
||||||
} else if (wsize < size) {
|
} else if (wsize < size) {
|
||||||
PERROR(_("%s: Unable to write %s\n"), progname, err_str);
|
|
||||||
errno = EPROTO;
|
errno = EPROTO;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -124,7 +121,7 @@ static int write_policy_buffer(int fd, int atomic,
|
|||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if (atomic) {
|
if (atomic) {
|
||||||
rc = write_buffer(fd, buffer, size, true);
|
rc = write_buffer(fd, buffer, size);
|
||||||
} else {
|
} else {
|
||||||
const char *b, *next;
|
const char *b, *next;
|
||||||
|
|
||||||
@@ -136,7 +133,7 @@ static int write_policy_buffer(int fd, int atomic,
|
|||||||
bsize = next - b;
|
bsize = next - b;
|
||||||
else
|
else
|
||||||
bsize = size;
|
bsize = size;
|
||||||
if (write_buffer(fd, b, bsize, false) == -1)
|
if (write_buffer(fd, b, bsize) == -1)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -147,83 +144,156 @@ static int write_policy_buffer(int fd, int atomic,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
#define AA_IFACE_FILE_LOAD ".load"
|
||||||
* open_option_iface - open the interface file for @option
|
#define AA_IFACE_FILE_REMOVE ".remove"
|
||||||
* @aadir: apparmorfs dir
|
#define AA_IFACE_FILE_REPLACE ".replace"
|
||||||
* @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;
|
|
||||||
|
|
||||||
switch (option) {
|
static int write_policy_buffer_to_iface(const char *iface_file,
|
||||||
case OPTION_ADD:
|
const char *buffer, size_t size)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
autoclose int dirfd = -1;
|
autoclose int dirfd = -1;
|
||||||
autoclose int fd = -1;
|
autoclose int fd = -1;
|
||||||
|
|
||||||
/* TODO: push backup into caller */
|
|
||||||
if (!kernel_load)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
dirfd = open_iface_dir();
|
dirfd = open_iface_dir();
|
||||||
if (dirfd == -1)
|
if (dirfd == -1)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
fd = open_option_iface(dirfd, option);
|
fd = openat(dirfd, iface_file, O_WRONLY | O_CLOEXEC);
|
||||||
if (fd == -1)
|
if (fd == -1)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
return write_policy_buffer(fd, kernel_supports_setload, buffer, size);
|
return write_policy_buffer(fd, kernel_supports_setload, buffer, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static int write_policy_fd_to_iface(const char *iface_file, int fd)
|
||||||
* 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)
|
|
||||||
{
|
{
|
||||||
autoclose int dirfd = -1;
|
autofree char *buffer = NULL;
|
||||||
autoclose int fd = -1;
|
int size = 0, asize = 0, rsize;
|
||||||
|
int chunksize = 1 << 14;
|
||||||
|
|
||||||
dirfd = open_iface_dir();
|
do {
|
||||||
if (dirfd == -1)
|
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;
|
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)
|
if (fd == -1)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
/* include trailing \0 in buffer write */
|
return write_policy_fd_to_iface(iface_file, fd);
|
||||||
return write_buffer(fd, fqname, strlen(fqname) + 1, 0);
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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);
|
||||||
}
|
}
|
||||||
|
@@ -20,7 +20,13 @@
|
|||||||
#define __AA_KERNEL_INTERFACE_H
|
#define __AA_KERNEL_INTERFACE_H
|
||||||
|
|
||||||
int aa_find_iface_dir(char **dir);
|
int aa_find_iface_dir(char **dir);
|
||||||
int aa_load_buffer(int option, char *buffer, int size);
|
int aa_kernel_interface_load_policy(const char *buffer, size_t size);
|
||||||
int aa_remove_profile(const char *fqname);
|
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 */
|
#endif /* __AA_KERNEL_INTERFACE_H */
|
||||||
|
@@ -522,7 +522,7 @@ int __sd_serialize_profile(int option, Profile *prof, int cache_fd)
|
|||||||
|
|
||||||
if (option == OPTION_REMOVE) {
|
if (option == OPTION_REMOVE) {
|
||||||
if (kernel_load) {
|
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;
|
error = -errno;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@@ -605,62 +605,55 @@ static void set_supported_features(void)
|
|||||||
|
|
||||||
int process_binary(int option, const char *profilename)
|
int process_binary(int option, const char *profilename)
|
||||||
{
|
{
|
||||||
autofree char *buffer = NULL;
|
const char *printed_name;
|
||||||
int retval = 0, size = 0, asize = 0, rsize;
|
int retval;
|
||||||
int chunksize = 1 << 14;
|
|
||||||
autoclose int fd = -1;
|
|
||||||
|
|
||||||
if (profilename) {
|
printed_name = profilename ? profilename : "stdin";
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
if (kernel_load) {
|
||||||
if (asize - size == 0) {
|
if (option == OPTION_ADD) {
|
||||||
buffer = (char *) realloc(buffer, chunksize);
|
retval = profilename ?
|
||||||
asize = chunksize;
|
aa_kernel_interface_load_policy_from_file(profilename) :
|
||||||
chunksize <<= 1;
|
aa_kernel_interface_load_policy_from_fd(0);
|
||||||
if (!buffer) {
|
if (retval == -1) {
|
||||||
PERROR(_("Memory allocation error."));
|
retval = errno;
|
||||||
return ENOMEM;
|
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) {
|
if (conf_verbose) {
|
||||||
switch (option) {
|
switch (option) {
|
||||||
case OPTION_ADD:
|
case OPTION_ADD:
|
||||||
printf(_("Cached load succeeded for \"%s\".\n"),
|
printf(_("Cached load succeeded for \"%s\".\n"),
|
||||||
profilename ? profilename : "stdin");
|
printed_name);
|
||||||
break;
|
break;
|
||||||
case OPTION_REPLACE:
|
case OPTION_REPLACE:
|
||||||
printf(_("Cached reload succeeded for \"%s\".\n"),
|
printf(_("Cached reload succeeded for \"%s\".\n"),
|
||||||
profilename ? profilename : "stdin");
|
printed_name);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return retval;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void reset_parser(const char *filename)
|
void reset_parser(const char *filename)
|
||||||
|
Reference in New Issue
Block a user