Skip to content

Commit 341c1fd

Browse files
committed
apparmor: make it so work buffers can be allocated from atomic context
In some situations AppArmor needs to be able to use its work buffers from atomic context. Add the ability to specify when in atomic context and hold a set of work buffers in reserve for atomic context to reduce the chance that a large work buffer allocation will need to be done. Fixes: df32333 ("apparmor: Use a memory pool instead per-CPU caches") Signed-off-by: John Johansen <[email protected]>
1 parent bce4e7e commit 341c1fd

File tree

6 files changed

+62
-38
lines changed

6 files changed

+62
-38
lines changed

security/apparmor/domain.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -896,7 +896,7 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
896896
ctx->nnp = aa_get_label(label);
897897

898898
/* buffer freed below, name is pointer into buffer */
899-
buffer = aa_get_buffer();
899+
buffer = aa_get_buffer(false);
900900
if (!buffer) {
901901
error = -ENOMEM;
902902
goto done;

security/apparmor/file.c

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ int aa_path_perm(const char *op, struct aa_label *label,
336336

337337
flags |= PATH_DELEGATE_DELETED | (S_ISDIR(cond->mode) ? PATH_IS_DIR :
338338
0);
339-
buffer = aa_get_buffer();
339+
buffer = aa_get_buffer(false);
340340
if (!buffer)
341341
return -ENOMEM;
342342
error = fn_for_each_confined(label, profile,
@@ -481,8 +481,8 @@ int aa_path_link(struct aa_label *label, struct dentry *old_dentry,
481481
int error;
482482

483483
/* buffer freed below, lname is pointer in buffer */
484-
buffer = aa_get_buffer();
485-
buffer2 = aa_get_buffer();
484+
buffer = aa_get_buffer(false);
485+
buffer2 = aa_get_buffer(false);
486486
error = -ENOMEM;
487487
if (!buffer || !buffer2)
488488
goto out;
@@ -519,7 +519,7 @@ static void update_file_ctx(struct aa_file_ctx *fctx, struct aa_label *label,
519519

520520
static int __file_path_perm(const char *op, struct aa_label *label,
521521
struct aa_label *flabel, struct file *file,
522-
u32 request, u32 denied)
522+
u32 request, u32 denied, bool in_atomic)
523523
{
524524
struct aa_profile *profile;
525525
struct aa_perms perms = {};
@@ -536,7 +536,7 @@ static int __file_path_perm(const char *op, struct aa_label *label,
536536
return 0;
537537

538538
flags = PATH_DELEGATE_DELETED | (S_ISDIR(cond.mode) ? PATH_IS_DIR : 0);
539-
buffer = aa_get_buffer();
539+
buffer = aa_get_buffer(in_atomic);
540540
if (!buffer)
541541
return -ENOMEM;
542542

@@ -604,11 +604,12 @@ static int __file_sock_perm(const char *op, struct aa_label *label,
604604
* @label: label being enforced (NOT NULL)
605605
* @file: file to revalidate access permissions on (NOT NULL)
606606
* @request: requested permissions
607+
* @in_atomic: whether allocations need to be done in atomic context
607608
*
608609
* Returns: %0 if access allowed else error
609610
*/
610611
int aa_file_perm(const char *op, struct aa_label *label, struct file *file,
611-
u32 request)
612+
u32 request, bool in_atomic)
612613
{
613614
struct aa_file_ctx *fctx;
614615
struct aa_label *flabel;
@@ -641,7 +642,7 @@ int aa_file_perm(const char *op, struct aa_label *label, struct file *file,
641642

642643
if (file->f_path.mnt && path_mediated_fs(file->f_path.dentry))
643644
error = __file_path_perm(op, label, flabel, file, request,
644-
denied);
645+
denied, in_atomic);
645646

646647
else if (S_ISSOCK(file_inode(file)->i_mode))
647648
error = __file_sock_perm(op, label, flabel, file, request,
@@ -669,7 +670,8 @@ static void revalidate_tty(struct aa_label *label)
669670
struct tty_file_private, list);
670671
file = file_priv->file;
671672

672-
if (aa_file_perm(OP_INHERIT, label, file, MAY_READ | MAY_WRITE))
673+
if (aa_file_perm(OP_INHERIT, label, file, MAY_READ | MAY_WRITE,
674+
IN_ATOMIC))
673675
drop_tty = 1;
674676
}
675677
spin_unlock(&tty->files_lock);
@@ -683,7 +685,8 @@ static int match_file(const void *p, struct file *file, unsigned int fd)
683685
{
684686
struct aa_label *label = (struct aa_label *)p;
685687

686-
if (aa_file_perm(OP_INHERIT, label, file, aa_map_file_to_perms(file)))
688+
if (aa_file_perm(OP_INHERIT, label, file, aa_map_file_to_perms(file),
689+
IN_ATOMIC))
687690
return fd + 1;
688691
return 0;
689692
}

security/apparmor/include/file.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ int aa_path_link(struct aa_label *label, struct dentry *old_dentry,
201201
const struct path *new_dir, struct dentry *new_dentry);
202202

203203
int aa_file_perm(const char *op, struct aa_label *label, struct file *file,
204-
u32 request);
204+
u32 request, bool in_atomic);
205205

206206
void aa_inherit_files(const struct cred *cred, struct files_struct *files);
207207

security/apparmor/include/path.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ int aa_path_name(const struct path *path, int flags, char *buffer,
2929
const char **name, const char **info,
3030
const char *disconnected);
3131

32-
char *aa_get_buffer(void);
32+
#define IN_ATOMIC true
33+
char *aa_get_buffer(bool in_atomic);
3334
void aa_put_buffer(char *buf);
3435

3536
#endif /* __AA_PATH_H */

security/apparmor/lsm.c

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ union aa_buffer {
5353
char buffer[1];
5454
};
5555

56+
#define RESERVE_COUNT 2
57+
static int reserve_count = RESERVE_COUNT;
58+
static int buffer_count;
59+
5660
static LIST_HEAD(aa_global_buffers);
5761
static DEFINE_SPINLOCK(aa_buffers_lock);
5862

@@ -452,7 +456,8 @@ static void apparmor_file_free_security(struct file *file)
452456
aa_put_label(rcu_access_pointer(ctx->label));
453457
}
454458

455-
static int common_file_perm(const char *op, struct file *file, u32 mask)
459+
static int common_file_perm(const char *op, struct file *file, u32 mask,
460+
bool in_atomic)
456461
{
457462
struct aa_label *label;
458463
int error = 0;
@@ -462,20 +467,21 @@ static int common_file_perm(const char *op, struct file *file, u32 mask)
462467
return -EACCES;
463468

464469
label = __begin_current_label_crit_section();
465-
error = aa_file_perm(op, label, file, mask);
470+
error = aa_file_perm(op, label, file, mask, in_atomic);
466471
__end_current_label_crit_section(label);
467472

468473
return error;
469474
}
470475

471476
static int apparmor_file_receive(struct file *file)
472477
{
473-
return common_file_perm(OP_FRECEIVE, file, aa_map_file_to_perms(file));
478+
return common_file_perm(OP_FRECEIVE, file, aa_map_file_to_perms(file),
479+
false);
474480
}
475481

476482
static int apparmor_file_permission(struct file *file, int mask)
477483
{
478-
return common_file_perm(OP_FPERM, file, mask);
484+
return common_file_perm(OP_FPERM, file, mask, false);
479485
}
480486

481487
static int apparmor_file_lock(struct file *file, unsigned int cmd)
@@ -485,11 +491,11 @@ static int apparmor_file_lock(struct file *file, unsigned int cmd)
485491
if (cmd == F_WRLCK)
486492
mask |= MAY_WRITE;
487493

488-
return common_file_perm(OP_FLOCK, file, mask);
494+
return common_file_perm(OP_FLOCK, file, mask, false);
489495
}
490496

491497
static int common_mmap(const char *op, struct file *file, unsigned long prot,
492-
unsigned long flags)
498+
unsigned long flags, bool in_atomic)
493499
{
494500
int mask = 0;
495501

@@ -507,20 +513,21 @@ static int common_mmap(const char *op, struct file *file, unsigned long prot,
507513
if (prot & PROT_EXEC)
508514
mask |= AA_EXEC_MMAP;
509515

510-
return common_file_perm(op, file, mask);
516+
return common_file_perm(op, file, mask, in_atomic);
511517
}
512518

513519
static int apparmor_mmap_file(struct file *file, unsigned long reqprot,
514520
unsigned long prot, unsigned long flags)
515521
{
516-
return common_mmap(OP_FMMAP, file, prot, flags);
522+
return common_mmap(OP_FMMAP, file, prot, flags, GFP_ATOMIC);
517523
}
518524

519525
static int apparmor_file_mprotect(struct vm_area_struct *vma,
520526
unsigned long reqprot, unsigned long prot)
521527
{
522528
return common_mmap(OP_FMPROT, vma->vm_file, prot,
523-
!(vma->vm_flags & VM_SHARED) ? MAP_PRIVATE : 0);
529+
!(vma->vm_flags & VM_SHARED) ? MAP_PRIVATE : 0,
530+
false);
524531
}
525532

526533
static int apparmor_sb_mount(const char *dev_name, const struct path *path,
@@ -1571,24 +1578,36 @@ static int param_set_mode(const char *val, const struct kernel_param *kp)
15711578
return 0;
15721579
}
15731580

1574-
char *aa_get_buffer(void)
1581+
char *aa_get_buffer(bool in_atomic)
15751582
{
15761583
union aa_buffer *aa_buf;
15771584
bool try_again = true;
1585+
gfp_t flags = (GFP_KERNEL | __GFP_RETRY_MAYFAIL | __GFP_NOWARN);
15781586

15791587
retry:
15801588
spin_lock(&aa_buffers_lock);
1581-
if (!list_empty(&aa_global_buffers)) {
1589+
if (buffer_count > reserve_count ||
1590+
(in_atomic && !list_empty(&aa_global_buffers))) {
15821591
aa_buf = list_first_entry(&aa_global_buffers, union aa_buffer,
15831592
list);
15841593
list_del(&aa_buf->list);
1594+
buffer_count--;
15851595
spin_unlock(&aa_buffers_lock);
15861596
return &aa_buf->buffer[0];
15871597
}
1598+
if (in_atomic) {
1599+
/*
1600+
* out of reserve buffers and in atomic context so increase
1601+
* how many buffers to keep in reserve
1602+
*/
1603+
reserve_count++;
1604+
flags = GFP_ATOMIC;
1605+
}
15881606
spin_unlock(&aa_buffers_lock);
15891607

1590-
aa_buf = kmalloc(aa_g_path_max, GFP_KERNEL | __GFP_RETRY_MAYFAIL |
1591-
__GFP_NOWARN);
1608+
if (!in_atomic)
1609+
might_sleep();
1610+
aa_buf = kmalloc(aa_g_path_max, flags);
15921611
if (!aa_buf) {
15931612
if (try_again) {
15941613
try_again = false;
@@ -1610,6 +1629,7 @@ void aa_put_buffer(char *buf)
16101629

16111630
spin_lock(&aa_buffers_lock);
16121631
list_add(&aa_buf->list, &aa_global_buffers);
1632+
buffer_count++;
16131633
spin_unlock(&aa_buffers_lock);
16141634
}
16151635

@@ -1661,9 +1681,9 @@ static int __init alloc_buffers(void)
16611681
* disabled early at boot if aa_g_path_max is extremly high.
16621682
*/
16631683
if (num_online_cpus() > 1)
1664-
num = 4;
1684+
num = 4 + RESERVE_COUNT;
16651685
else
1666-
num = 2;
1686+
num = 2 + RESERVE_COUNT;
16671687

16681688
for (i = 0; i < num; i++) {
16691689

security/apparmor/mount.c

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,7 @@ int aa_remount(struct aa_label *label, const struct path *path,
412412

413413
binary = path->dentry->d_sb->s_type->fs_flags & FS_BINARY_MOUNTDATA;
414414

415-
buffer = aa_get_buffer();
415+
buffer = aa_get_buffer(false);
416416
if (!buffer)
417417
return -ENOMEM;
418418
error = fn_for_each_confined(label, profile,
@@ -443,8 +443,8 @@ int aa_bind_mount(struct aa_label *label, const struct path *path,
443443
if (error)
444444
return error;
445445

446-
buffer = aa_get_buffer();
447-
old_buffer = aa_get_buffer();
446+
buffer = aa_get_buffer(false);
447+
old_buffer = aa_get_buffer(false);
448448
error = -ENOMEM;
449449
if (!buffer || old_buffer)
450450
goto out;
@@ -474,7 +474,7 @@ int aa_mount_change_type(struct aa_label *label, const struct path *path,
474474
flags &= (MS_REC | MS_SILENT | MS_SHARED | MS_PRIVATE | MS_SLAVE |
475475
MS_UNBINDABLE);
476476

477-
buffer = aa_get_buffer();
477+
buffer = aa_get_buffer(false);
478478
if (!buffer)
479479
return -ENOMEM;
480480
error = fn_for_each_confined(label, profile,
@@ -503,8 +503,8 @@ int aa_move_mount(struct aa_label *label, const struct path *path,
503503
if (error)
504504
return error;
505505

506-
buffer = aa_get_buffer();
507-
old_buffer = aa_get_buffer();
506+
buffer = aa_get_buffer(false);
507+
old_buffer = aa_get_buffer(false);
508508
error = -ENOMEM;
509509
if (!buffer || !old_buffer)
510510
goto out;
@@ -554,13 +554,13 @@ int aa_new_mount(struct aa_label *label, const char *dev_name,
554554
}
555555
}
556556

557-
buffer = aa_get_buffer();
557+
buffer = aa_get_buffer(false);
558558
if (!buffer) {
559559
error = -ENOMEM;
560560
goto out;
561561
}
562562
if (dev_path) {
563-
dev_buffer = aa_get_buffer();
563+
dev_buffer = aa_get_buffer(false);
564564
if (!dev_buffer) {
565565
error = -ENOMEM;
566566
goto out;
@@ -624,7 +624,7 @@ int aa_umount(struct aa_label *label, struct vfsmount *mnt, int flags)
624624
AA_BUG(!label);
625625
AA_BUG(!mnt);
626626

627-
buffer = aa_get_buffer();
627+
buffer = aa_get_buffer(false);
628628
if (!buffer)
629629
return -ENOMEM;
630630

@@ -703,8 +703,8 @@ int aa_pivotroot(struct aa_label *label, const struct path *old_path,
703703
AA_BUG(!old_path);
704704
AA_BUG(!new_path);
705705

706-
old_buffer = aa_get_buffer();
707-
new_buffer = aa_get_buffer();
706+
old_buffer = aa_get_buffer(false);
707+
new_buffer = aa_get_buffer(false);
708708
error = -ENOMEM;
709709
if (!old_buffer || !new_buffer)
710710
goto out;

0 commit comments

Comments
 (0)