From ea08eeccae9297f7aabd2ef7f0c2517ac4549acc Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Tue, 20 Feb 2024 01:18:26 +0000
Subject: [PATCH] write in 30M
---
kernel/security/apparmor/apparmorfs.c | 241 +++++++++++++++++++++++++++++++++--------------
1 files changed, 168 insertions(+), 73 deletions(-)
diff --git a/kernel/security/apparmor/apparmorfs.c b/kernel/security/apparmor/apparmorfs.c
index 900c865..49d97b3 100644
--- a/kernel/security/apparmor/apparmorfs.c
+++ b/kernel/security/apparmor/apparmorfs.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* AppArmor security module
*
@@ -5,17 +6,12 @@
*
* Copyright (C) 1998-2008 Novell/SUSE
* Copyright 2009-2010 Canonical Ltd.
- *
- * 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, version 2 of the
- * License.
*/
#include <linux/ctype.h>
#include <linux/security.h>
#include <linux/vmalloc.h>
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/seq_file.h>
#include <linux/uaccess.h>
#include <linux/mount.h>
@@ -23,7 +19,9 @@
#include <linux/capability.h>
#include <linux/rcupdate.h>
#include <linux/fs.h>
+#include <linux/fs_context.h>
#include <linux/poll.h>
+#include <linux/zlib.h>
#include <uapi/linux/major.h>
#include <uapi/linux/magic.h>
@@ -67,6 +65,35 @@
/*
* support fns
*/
+
+struct rawdata_f_data {
+ struct aa_loaddata *loaddata;
+};
+
+#define RAWDATA_F_DATA_BUF(p) (char *)(p + 1)
+
+static void rawdata_f_data_free(struct rawdata_f_data *private)
+{
+ if (!private)
+ return;
+
+ aa_put_loaddata(private->loaddata);
+ kvfree(private);
+}
+
+static struct rawdata_f_data *rawdata_f_data_alloc(size_t size)
+{
+ struct rawdata_f_data *ret;
+
+ if (size > SIZE_MAX - sizeof(*ret))
+ return ERR_PTR(-EINVAL);
+
+ ret = kvzalloc(sizeof(*ret) + size, GFP_KERNEL);
+ if (!ret)
+ return ERR_PTR(-ENOMEM);
+
+ return ret;
+}
/**
* aa_mangle_name - mangle a profile name to std profile layout form
@@ -123,26 +150,20 @@
return 0;
}
-static void aafs_i_callback(struct rcu_head *head)
+static void aafs_free_inode(struct inode *inode)
{
- struct inode *inode = container_of(head, struct inode, i_rcu);
if (S_ISLNK(inode->i_mode))
kfree(inode->i_link);
free_inode_nonrcu(inode);
}
-static void aafs_destroy_inode(struct inode *inode)
-{
- call_rcu(&inode->i_rcu, aafs_i_callback);
-}
-
static const struct super_operations aafs_super_ops = {
.statfs = simple_statfs,
- .destroy_inode = aafs_destroy_inode,
+ .free_inode = aafs_free_inode,
.show_path = aafs_show_path,
};
-static int fill_super(struct super_block *sb, void *data, int silent)
+static int apparmorfs_fill_super(struct super_block *sb, struct fs_context *fc)
{
static struct tree_descr files[] = { {""} };
int error;
@@ -155,16 +176,25 @@
return 0;
}
-static struct dentry *aafs_mount(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
+static int apparmorfs_get_tree(struct fs_context *fc)
{
- return mount_single(fs_type, flags, data, fill_super);
+ return get_tree_single(fc, apparmorfs_fill_super);
+}
+
+static const struct fs_context_operations apparmorfs_context_ops = {
+ .get_tree = apparmorfs_get_tree,
+};
+
+static int apparmorfs_init_fs_context(struct fs_context *fc)
+{
+ fc->ops = &apparmorfs_context_ops;
+ return 0;
}
static struct file_system_type aafs_ops = {
.owner = THIS_MODULE,
.name = AAFS_NAME,
- .mount = aafs_mount,
+ .init_fs_context = apparmorfs_init_fs_context,
.kill_sb = kill_anon_super,
};
@@ -311,38 +341,6 @@
}
/**
- * aafs_create_symlink - create a symlink in the apparmorfs filesystem
- * @name: name of dentry to create
- * @parent: parent directory for this dentry
- * @target: if symlink, symlink target string
- * @private: private data
- * @iops: struct of inode_operations that should be used
- *
- * If @target parameter is %NULL, then the @iops parameter needs to be
- * setup to handle .readlink and .get_link inode_operations.
- */
-static struct dentry *aafs_create_symlink(const char *name,
- struct dentry *parent,
- const char *target,
- void *private,
- const struct inode_operations *iops)
-{
- struct dentry *dent;
- char *link = NULL;
-
- if (target) {
- if (!link)
- return ERR_PTR(-ENOMEM);
- }
- dent = aafs_create(name, S_IFLNK | 0444, parent, private, link, NULL,
- iops);
- if (IS_ERR(dent))
- kfree(link);
-
- return dent;
-}
-
-/**
* aafs_remove - removes a file or directory from the apparmorfs filesystem
*
* @dentry: dentry of the file/directory/symlink to removed.
@@ -403,7 +401,7 @@
data->size = copy_size;
if (copy_from_user(data->data, userbuf, copy_size)) {
- kvfree(data);
+ aa_put_loaddata(data);
return ERR_PTR(-EFAULT);
}
@@ -594,7 +592,7 @@
void __aa_bump_ns_revision(struct aa_ns *ns)
{
- WRITE_ONCE(ns->revision, ns->revision + 1);
+ WRITE_ONCE(ns->revision, READ_ONCE(ns->revision) + 1);
wake_up_interruptible(&ns->wait);
}
@@ -810,7 +808,7 @@
struct multi_transaction {
struct kref count;
ssize_t size;
- char data[0];
+ char data[];
};
#define MULTI_TRANSACTION_LIMIT (PAGE_SIZE - sizeof(struct multi_transaction))
@@ -869,8 +867,10 @@
if (!t)
return ERR_PTR(-ENOMEM);
kref_init(&t->count);
- if (copy_from_user(t->data, buf, size))
+ if (copy_from_user(t->data, buf, size)) {
+ put_multi_transaction(t);
return ERR_PTR(-EFAULT);
+ }
return t;
}
@@ -1281,36 +1281,117 @@
return 0;
}
+static int seq_rawdata_compressed_size_show(struct seq_file *seq, void *v)
+{
+ struct aa_loaddata *data = seq->private;
+
+ seq_printf(seq, "%zu\n", data->compressed_size);
+
+ return 0;
+}
+
SEQ_RAWDATA_FOPS(abi);
SEQ_RAWDATA_FOPS(revision);
SEQ_RAWDATA_FOPS(hash);
+SEQ_RAWDATA_FOPS(compressed_size);
+
+static int deflate_decompress(char *src, size_t slen, char *dst, size_t dlen)
+{
+ int error;
+ struct z_stream_s strm;
+
+ if (aa_g_rawdata_compression_level == 0) {
+ if (dlen < slen)
+ return -EINVAL;
+ memcpy(dst, src, slen);
+ return 0;
+ }
+
+ memset(&strm, 0, sizeof(strm));
+
+ strm.workspace = kvzalloc(zlib_inflate_workspacesize(), GFP_KERNEL);
+ if (!strm.workspace)
+ return -ENOMEM;
+
+ strm.next_in = src;
+ strm.avail_in = slen;
+
+ error = zlib_inflateInit(&strm);
+ if (error != Z_OK) {
+ error = -ENOMEM;
+ goto fail_inflate_init;
+ }
+
+ strm.next_out = dst;
+ strm.avail_out = dlen;
+
+ error = zlib_inflate(&strm, Z_FINISH);
+ if (error != Z_STREAM_END)
+ error = -EINVAL;
+ else
+ error = 0;
+
+ zlib_inflateEnd(&strm);
+fail_inflate_init:
+ kvfree(strm.workspace);
+ return error;
+}
static ssize_t rawdata_read(struct file *file, char __user *buf, size_t size,
loff_t *ppos)
{
- struct aa_loaddata *rawdata = file->private_data;
+ struct rawdata_f_data *private = file->private_data;
- return simple_read_from_buffer(buf, size, ppos, rawdata->data,
- rawdata->size);
+ return simple_read_from_buffer(buf, size, ppos,
+ RAWDATA_F_DATA_BUF(private),
+ private->loaddata->size);
}
static int rawdata_release(struct inode *inode, struct file *file)
{
- aa_put_loaddata(file->private_data);
+ rawdata_f_data_free(file->private_data);
return 0;
}
static int rawdata_open(struct inode *inode, struct file *file)
{
+ int error;
+ struct aa_loaddata *loaddata;
+ struct rawdata_f_data *private;
+
if (!policy_view_capable(NULL))
return -EACCES;
- file->private_data = __aa_get_loaddata(inode->i_private);
- if (!file->private_data)
+
+ loaddata = __aa_get_loaddata(inode->i_private);
+ if (!loaddata)
/* lost race: this entry is being reaped */
return -ENOENT;
+ private = rawdata_f_data_alloc(loaddata->size);
+ if (IS_ERR(private)) {
+ error = PTR_ERR(private);
+ goto fail_private_alloc;
+ }
+
+ private->loaddata = loaddata;
+
+ error = deflate_decompress(loaddata->data, loaddata->compressed_size,
+ RAWDATA_F_DATA_BUF(private),
+ loaddata->size);
+ if (error)
+ goto fail_decompress;
+
+ file->private_data = private;
return 0;
+
+fail_decompress:
+ rawdata_f_data_free(private);
+ return error;
+
+fail_private_alloc:
+ aa_put_loaddata(loaddata);
+ return error;
}
static const struct file_operations rawdata_fops = {
@@ -1388,6 +1469,13 @@
goto fail;
rawdata->dents[AAFS_LOADDATA_HASH] = dent;
}
+
+ dent = aafs_create_file("compressed_size", S_IFREG | 0444, dir,
+ rawdata,
+ &seq_rawdata_compressed_size_fops);
+ if (IS_ERR(dent))
+ goto fail;
+ rawdata->dents[AAFS_LOADDATA_COMPRESSED_SIZE] = dent;
dent = aafs_create_file("raw_data", S_IFREG | 0444,
dir, rawdata, &rawdata_fops);
@@ -1645,25 +1733,25 @@
}
if (profile->rawdata) {
- dent = aafs_create_symlink("raw_sha1", dir, NULL,
- profile->label.proxy,
- &rawdata_link_sha1_iops);
+ dent = aafs_create("raw_sha1", S_IFLNK | 0444, dir,
+ profile->label.proxy, NULL, NULL,
+ &rawdata_link_sha1_iops);
if (IS_ERR(dent))
goto fail;
aa_get_proxy(profile->label.proxy);
profile->dents[AAFS_PROF_RAW_HASH] = dent;
- dent = aafs_create_symlink("raw_abi", dir, NULL,
- profile->label.proxy,
- &rawdata_link_abi_iops);
+ dent = aafs_create("raw_abi", S_IFLNK | 0444, dir,
+ profile->label.proxy, NULL, NULL,
+ &rawdata_link_abi_iops);
if (IS_ERR(dent))
goto fail;
aa_get_proxy(profile->label.proxy);
profile->dents[AAFS_PROF_RAW_ABI] = dent;
- dent = aafs_create_symlink("raw_data", dir, NULL,
- profile->label.proxy,
- &rawdata_link_data_iops);
+ dent = aafs_create("raw_data", S_IFLNK | 0444, dir,
+ profile->label.proxy, NULL, NULL,
+ &rawdata_link_data_iops);
if (IS_ERR(dent))
goto fail;
aa_get_proxy(profile->label.proxy);
@@ -1749,7 +1837,7 @@
if (error)
return error;
- parent = aa_get_ns(dir->i_private);
+ parent = aa_get_ns(dir->i_private);
/* rmdir calls the generic securityfs functions to remove files
* from the apparmor dir. It is up to the apparmor ns locking
* to avoid races.
@@ -1959,6 +2047,9 @@
return error;
}
+
+
+#define list_entry_is_head(pos, head, member) (&pos->member == (head))
/**
* __next_ns - find the next namespace to list
@@ -2243,6 +2334,8 @@
static struct aa_sfs_entry aa_sfs_entry_policy[] = {
AA_SFS_DIR("versions", aa_sfs_entry_versions),
AA_SFS_FILE_BOOLEAN("set_load", 1),
+ /* number of out of band transitions supported */
+ AA_SFS_FILE_U64("outofband", MAX_OOB_SUPPORTED),
{ }
};
@@ -2453,16 +2546,18 @@
{
struct aa_ns *ns;
struct path path;
+ int error;
if (!dentry)
return ERR_PTR(-ECHILD);
+
ns = aa_get_current_ns();
path.mnt = mntget(aafs_mnt);
path.dentry = dget(ns_dir(ns));
- nd_jump_link(&path);
+ error = nd_jump_link(&path);
aa_put_ns(ns);
- return NULL;
+ return ERR_PTR(error);
}
static int policy_readlink(struct dentry *dentry, char __user *buffer,
--
Gitblit v1.6.2