@@ -103,48 +103,50 @@ struct bsd_acct_struct {
103
103
atomic_long_t count ;
104
104
struct rcu_head rcu ;
105
105
struct mutex lock ;
106
- int active ;
106
+ bool active ;
107
+ bool check_space ;
107
108
unsigned long needcheck ;
108
109
struct file * file ;
109
110
struct pid_namespace * ns ;
110
111
struct work_struct work ;
111
112
struct completion done ;
113
+ acct_t ac ;
112
114
};
113
115
114
- static void do_acct_process (struct bsd_acct_struct * acct );
116
+ static void fill_ac (struct bsd_acct_struct * acct );
117
+ static void acct_write_process (struct bsd_acct_struct * acct );
115
118
116
119
/*
117
120
* Check the amount of free space and suspend/resume accordingly.
118
121
*/
119
- static int check_free_space (struct bsd_acct_struct * acct )
122
+ static bool check_free_space (struct bsd_acct_struct * acct )
120
123
{
121
124
struct kstatfs sbuf ;
122
125
123
- if (time_is_after_jiffies ( acct -> needcheck ) )
124
- goto out ;
126
+ if (! acct -> check_space )
127
+ return acct -> active ;
125
128
126
129
/* May block */
127
130
if (vfs_statfs (& acct -> file -> f_path , & sbuf ))
128
- goto out ;
131
+ return acct -> active ;
129
132
130
133
if (acct -> active ) {
131
134
u64 suspend = sbuf .f_blocks * SUSPEND ;
132
135
do_div (suspend , 100 );
133
136
if (sbuf .f_bavail <= suspend ) {
134
- acct -> active = 0 ;
137
+ acct -> active = false ;
135
138
pr_info ("Process accounting paused\n" );
136
139
}
137
140
} else {
138
141
u64 resume = sbuf .f_blocks * RESUME ;
139
142
do_div (resume , 100 );
140
143
if (sbuf .f_bavail >= resume ) {
141
- acct -> active = 1 ;
144
+ acct -> active = true ;
142
145
pr_info ("Process accounting resumed\n" );
143
146
}
144
147
}
145
148
146
149
acct -> needcheck = jiffies + ACCT_TIMEOUT * HZ ;
147
- out :
148
150
return acct -> active ;
149
151
}
150
152
@@ -189,7 +191,11 @@ static void acct_pin_kill(struct fs_pin *pin)
189
191
{
190
192
struct bsd_acct_struct * acct = to_acct (pin );
191
193
mutex_lock (& acct -> lock );
192
- do_acct_process (acct );
194
+ /*
195
+ * Fill the accounting struct with the exiting task's info
196
+ * before punting to the workqueue.
197
+ */
198
+ fill_ac (acct );
193
199
schedule_work (& acct -> work );
194
200
wait_for_completion (& acct -> done );
195
201
cmpxchg (& acct -> ns -> bacct , pin , NULL );
@@ -202,6 +208,9 @@ static void close_work(struct work_struct *work)
202
208
{
203
209
struct bsd_acct_struct * acct = container_of (work , struct bsd_acct_struct , work );
204
210
struct file * file = acct -> file ;
211
+
212
+ /* We were fired by acct_pin_kill() which holds acct->lock. */
213
+ acct_write_process (acct );
205
214
if (file -> f_op -> flush )
206
215
file -> f_op -> flush (file , NULL );
207
216
__fput_sync (file );
@@ -234,6 +243,20 @@ static int acct_on(struct filename *pathname)
234
243
return - EACCES ;
235
244
}
236
245
246
+ /* Exclude kernel kernel internal filesystems. */
247
+ if (file_inode (file )-> i_sb -> s_flags & (SB_NOUSER | SB_KERNMOUNT )) {
248
+ kfree (acct );
249
+ filp_close (file , NULL );
250
+ return - EINVAL ;
251
+ }
252
+
253
+ /* Exclude procfs and sysfs. */
254
+ if (file_inode (file )-> i_sb -> s_iflags & SB_I_USERNS_VISIBLE ) {
255
+ kfree (acct );
256
+ filp_close (file , NULL );
257
+ return - EINVAL ;
258
+ }
259
+
237
260
if (!(file -> f_mode & FMODE_CAN_WRITE )) {
238
261
kfree (acct );
239
262
filp_close (file , NULL );
@@ -430,13 +453,27 @@ static u32 encode_float(u64 value)
430
453
* do_exit() or when switching to a different output file.
431
454
*/
432
455
433
- static void fill_ac (acct_t * ac )
456
+ static void fill_ac (struct bsd_acct_struct * acct )
434
457
{
435
458
struct pacct_struct * pacct = & current -> signal -> pacct ;
459
+ struct file * file = acct -> file ;
460
+ acct_t * ac = & acct -> ac ;
436
461
u64 elapsed , run_time ;
437
462
time64_t btime ;
438
463
struct tty_struct * tty ;
439
464
465
+ lockdep_assert_held (& acct -> lock );
466
+
467
+ if (time_is_after_jiffies (acct -> needcheck )) {
468
+ acct -> check_space = false;
469
+
470
+ /* Don't fill in @ac if nothing will be written. */
471
+ if (!acct -> active )
472
+ return ;
473
+ } else {
474
+ acct -> check_space = true;
475
+ }
476
+
440
477
/*
441
478
* Fill the accounting struct with the needed info as recorded
442
479
* by the different kernel functions.
@@ -484,64 +521,61 @@ static void fill_ac(acct_t *ac)
484
521
ac -> ac_majflt = encode_comp_t (pacct -> ac_majflt );
485
522
ac -> ac_exitcode = pacct -> ac_exitcode ;
486
523
spin_unlock_irq (& current -> sighand -> siglock );
487
- }
488
- /*
489
- * do_acct_process does all actual work. Caller holds the reference to file.
490
- */
491
- static void do_acct_process (struct bsd_acct_struct * acct )
492
- {
493
- acct_t ac ;
494
- unsigned long flim ;
495
- const struct cred * orig_cred ;
496
- struct file * file = acct -> file ;
497
524
498
- /*
499
- * Accounting records are not subject to resource limits.
500
- */
501
- flim = rlimit (RLIMIT_FSIZE );
502
- current -> signal -> rlim [RLIMIT_FSIZE ].rlim_cur = RLIM_INFINITY ;
503
- /* Perform file operations on behalf of whoever enabled accounting */
504
- orig_cred = override_creds (file -> f_cred );
505
-
506
- /*
507
- * First check to see if there is enough free_space to continue
508
- * the process accounting system.
509
- */
510
- if (!check_free_space (acct ))
511
- goto out ;
512
-
513
- fill_ac (& ac );
514
525
/* we really need to bite the bullet and change layout */
515
- ac . ac_uid = from_kuid_munged (file -> f_cred -> user_ns , orig_cred -> uid );
516
- ac . ac_gid = from_kgid_munged (file -> f_cred -> user_ns , orig_cred -> gid );
526
+ ac -> ac_uid = from_kuid_munged (file -> f_cred -> user_ns , current_uid () );
527
+ ac -> ac_gid = from_kgid_munged (file -> f_cred -> user_ns , current_gid () );
517
528
#if ACCT_VERSION == 1 || ACCT_VERSION == 2
518
529
/* backward-compatible 16 bit fields */
519
- ac . ac_uid16 = ac . ac_uid ;
520
- ac . ac_gid16 = ac . ac_gid ;
530
+ ac -> ac_uid16 = ac -> ac_uid ;
531
+ ac -> ac_gid16 = ac -> ac_gid ;
521
532
#elif ACCT_VERSION == 3
522
533
{
523
534
struct pid_namespace * ns = acct -> ns ;
524
535
525
- ac . ac_pid = task_tgid_nr_ns (current , ns );
536
+ ac -> ac_pid = task_tgid_nr_ns (current , ns );
526
537
rcu_read_lock ();
527
- ac .ac_ppid = task_tgid_nr_ns (rcu_dereference (current -> real_parent ),
528
- ns );
538
+ ac -> ac_ppid = task_tgid_nr_ns (rcu_dereference (current -> real_parent ), ns );
529
539
rcu_read_unlock ();
530
540
}
531
541
#endif
542
+ }
543
+
544
+ static void acct_write_process (struct bsd_acct_struct * acct )
545
+ {
546
+ struct file * file = acct -> file ;
547
+ const struct cred * cred ;
548
+ acct_t * ac = & acct -> ac ;
549
+
550
+ /* Perform file operations on behalf of whoever enabled accounting */
551
+ cred = override_creds (file -> f_cred );
552
+
532
553
/*
533
- * Get freeze protection. If the fs is frozen, just skip the write
534
- * as we could deadlock the system otherwise.
554
+ * First check to see if there is enough free_space to continue
555
+ * the process accounting system. Then get freeze protection. If
556
+ * the fs is frozen, just skip the write as we could deadlock
557
+ * the system otherwise.
535
558
*/
536
- if (file_start_write_trylock (file )) {
559
+ if (check_free_space ( acct ) && file_start_write_trylock (file )) {
537
560
/* it's been opened O_APPEND, so position is irrelevant */
538
561
loff_t pos = 0 ;
539
- __kernel_write (file , & ac , sizeof (acct_t ), & pos );
562
+ __kernel_write (file , ac , sizeof (acct_t ), & pos );
540
563
file_end_write (file );
541
564
}
542
- out :
565
+
566
+ revert_creds (cred );
567
+ }
568
+
569
+ static void do_acct_process (struct bsd_acct_struct * acct )
570
+ {
571
+ unsigned long flim ;
572
+
573
+ /* Accounting records are not subject to resource limits. */
574
+ flim = rlimit (RLIMIT_FSIZE );
575
+ current -> signal -> rlim [RLIMIT_FSIZE ].rlim_cur = RLIM_INFINITY ;
576
+ fill_ac (acct );
577
+ acct_write_process (acct );
543
578
current -> signal -> rlim [RLIMIT_FSIZE ].rlim_cur = flim ;
544
- revert_creds (orig_cred );
545
579
}
546
580
547
581
/**
0 commit comments