Merge tag 'apparmor-pr-2019-12-03' of git://git.kernel.org/pub/scm/linux/kernel/git...
[sfrench/cifs-2.6.git] / security / apparmor / file.c
index 4c1b05eb130c32422c238089dd61c539037d30f8..fe2ebe5e865efcb14a4b84352e006b247f5ec2f2 100644 (file)
@@ -76,7 +76,7 @@ static void file_audit_cb(struct audit_buffer *ab, void *va)
        if (aad(sa)->peer) {
                audit_log_format(ab, " target=");
                aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer,
-                               FLAG_VIEW_SUBNS, GFP_ATOMIC);
+                               FLAG_VIEW_SUBNS, GFP_KERNEL);
        } else if (aad(sa)->fs.target) {
                audit_log_format(ab, " target=");
                audit_log_untrustedstring(ab, aad(sa)->fs.target);
@@ -332,12 +332,14 @@ int aa_path_perm(const char *op, struct aa_label *label,
 
        flags |= PATH_DELEGATE_DELETED | (S_ISDIR(cond->mode) ? PATH_IS_DIR :
                                                                0);
-       get_buffers(buffer);
+       buffer = aa_get_buffer(false);
+       if (!buffer)
+               return -ENOMEM;
        error = fn_for_each_confined(label, profile,
                        profile_path_perm(op, profile, path, buffer, request,
                                          cond, flags, &perms));
 
-       put_buffers(buffer);
+       aa_put_buffer(buffer);
 
        return error;
 }
@@ -475,12 +477,18 @@ int aa_path_link(struct aa_label *label, struct dentry *old_dentry,
        int error;
 
        /* buffer freed below, lname is pointer in buffer */
-       get_buffers(buffer, buffer2);
+       buffer = aa_get_buffer(false);
+       buffer2 = aa_get_buffer(false);
+       error = -ENOMEM;
+       if (!buffer || !buffer2)
+               goto out;
+
        error = fn_for_each_confined(label, profile,
                        profile_path_link(profile, &link, buffer, &target,
                                          buffer2, &cond));
-       put_buffers(buffer, buffer2);
-
+out:
+       aa_put_buffer(buffer);
+       aa_put_buffer(buffer2);
        return error;
 }
 
@@ -507,7 +515,7 @@ static void update_file_ctx(struct aa_file_ctx *fctx, struct aa_label *label,
 
 static int __file_path_perm(const char *op, struct aa_label *label,
                            struct aa_label *flabel, struct file *file,
-                           u32 request, u32 denied)
+                           u32 request, u32 denied, bool in_atomic)
 {
        struct aa_profile *profile;
        struct aa_perms perms = {};
@@ -524,7 +532,9 @@ static int __file_path_perm(const char *op, struct aa_label *label,
                return 0;
 
        flags = PATH_DELEGATE_DELETED | (S_ISDIR(cond.mode) ? PATH_IS_DIR : 0);
-       get_buffers(buffer);
+       buffer = aa_get_buffer(in_atomic);
+       if (!buffer)
+               return -ENOMEM;
 
        /* check every profile in task label not in current cache */
        error = fn_for_each_not_in_set(flabel, label, profile,
@@ -553,7 +563,7 @@ static int __file_path_perm(const char *op, struct aa_label *label,
        if (!error)
                update_file_ctx(file_ctx(file), label, request);
 
-       put_buffers(buffer);
+       aa_put_buffer(buffer);
 
        return error;
 }
@@ -590,11 +600,12 @@ static int __file_sock_perm(const char *op, struct aa_label *label,
  * @label: label being enforced   (NOT NULL)
  * @file: file to revalidate access permissions on  (NOT NULL)
  * @request: requested permissions
+ * @in_atomic: whether allocations need to be done in atomic context
  *
  * Returns: %0 if access allowed else error
  */
 int aa_file_perm(const char *op, struct aa_label *label, struct file *file,
-                u32 request)
+                u32 request, bool in_atomic)
 {
        struct aa_file_ctx *fctx;
        struct aa_label *flabel;
@@ -607,7 +618,8 @@ int aa_file_perm(const char *op, struct aa_label *label, struct file *file,
        fctx = file_ctx(file);
 
        rcu_read_lock();
-       flabel  = rcu_dereference(fctx->label);
+       flabel  = aa_get_newest_label(rcu_dereference(fctx->label));
+       rcu_read_unlock();
        AA_BUG(!flabel);
 
        /* revalidate access, if task is unconfined, or the cached cred
@@ -626,14 +638,13 @@ int aa_file_perm(const char *op, struct aa_label *label, struct file *file,
 
        if (file->f_path.mnt && path_mediated_fs(file->f_path.dentry))
                error = __file_path_perm(op, label, flabel, file, request,
-                                        denied);
+                                        denied, in_atomic);
 
        else if (S_ISSOCK(file_inode(file)->i_mode))
                error = __file_sock_perm(op, label, flabel, file, request,
                                         denied);
 done:
-       rcu_read_unlock();
-
+       aa_put_label(flabel);
        return error;
 }
 
@@ -655,7 +666,8 @@ static void revalidate_tty(struct aa_label *label)
                                             struct tty_file_private, list);
                file = file_priv->file;
 
-               if (aa_file_perm(OP_INHERIT, label, file, MAY_READ | MAY_WRITE))
+               if (aa_file_perm(OP_INHERIT, label, file, MAY_READ | MAY_WRITE,
+                                IN_ATOMIC))
                        drop_tty = 1;
        }
        spin_unlock(&tty->files_lock);
@@ -669,7 +681,8 @@ static int match_file(const void *p, struct file *file, unsigned int fd)
 {
        struct aa_label *label = (struct aa_label *)p;
 
-       if (aa_file_perm(OP_INHERIT, label, file, aa_map_file_to_perms(file)))
+       if (aa_file_perm(OP_INHERIT, label, file, aa_map_file_to_perms(file),
+                        IN_ATOMIC))
                return fd + 1;
        return 0;
 }