]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/commitdiff
UBUNTU: SAUCE: apparmor: fix replacement race in reading rawdata
authorJohn Johansen <john.johansen@canonical.com>
Fri, 31 Mar 2017 13:25:27 +0000 (06:25 -0700)
committerThadeu Lima de Souza Cascardo <cascardo@canonical.com>
Thu, 6 Apr 2017 08:26:16 +0000 (09:26 +0100)
The reading of rawdata is subject to a replacement race when the
rawdata is read in chunks smaller than the data size.

For each read the profile proxy is rechecked for the newest profile;
Which means if a profile is replaced between reads later chunks will
contain data from the new version of the profile while the earlier
reads will contain data from the previous version. This can result in
data that is inconsistent and corrupt.

Instead of rechecking for the current profile at each read. Get the
current profile at the time of the open and use the rawdata of the
profile for the lifetime that the file handle is open.

BugLink: http://bugs.launchpad.net/bugs/1638996
Signed-off-by: John Johansen <john.johansen@canonical.com>
Acked-by: Stefan Bader <stefan.bader@canonical.com>
Acked-by: Tim Gardner <tim.gardner@canonical.com>
Acked-by: Brad Figg <brad.figg@canonical.com>
Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@canonical.com>
security/apparmor/apparmorfs.c

index f6a2370b375803681f4f247a473f7a9798ba4c38..6950d27105e6aa5a3626498c5f72e6c45cdac848 100644 (file)
@@ -766,7 +766,7 @@ static const struct file_operations aa_fs_ns_name = {
 static int rawdata_release(struct inode *inode, struct file *file)
 {
        /* TODO: switch to loaddata when profile switched to symlink */
-       aa_put_proxy(file->private_data);
+       aa_put_loaddata(file->private_data);
 
        return 0;
 }
@@ -832,22 +832,24 @@ static const struct file_operations aa_fs_seq_raw_hash_fops = {
 static ssize_t rawdata_read(struct file *file, char __user *buf, size_t size,
                            loff_t *ppos)
 {
-       struct aa_proxy *proxy = file->private_data;
-       struct aa_label *label = aa_get_label_rcu(&proxy->label);
-       struct aa_profile *profile = labels_profile(label);
+       struct aa_loaddata *rawdata = file->private_data;
 
-       ssize_t ret = simple_read_from_buffer(buf, size, ppos, profile->rawdata->data, profile->rawdata->size);
-       aa_put_label(label);
-
-       return ret;
+       return simple_read_from_buffer(buf, size, ppos, rawdata->data,
+                                      rawdata->size);
 }
 
 static int rawdata_open(struct inode *inode, struct file *file)
 {
+       struct aa_proxy *proxy = inode->i_private;
+       struct aa_label *label;
+       struct aa_profile *profile;
+
        if (!policy_view_capable(NULL))
                return -EACCES;
-
-       file->private_data = aa_get_proxy(inode->i_private);
+       label = aa_get_label_rcu(&proxy->label);
+       profile = labels_profile(label);
+       file->private_data = aa_get_loaddata(profile->rawdata);
+       aa_put_label(label);
 
        return 0;
 }