1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * AppArmor security module 4 * 5 * This file contains AppArmor mediation of files 6 * 7 * Copyright (C) 1998-2008 Novell/SUSE 8 * Copyright 2009-2010 Canonical Ltd. 9 */ 10 11 #include <linux/tty.h> 12 #include <linux/fdtable.h> 13 #include <linux/file.h> 14 15 #include "include/apparmor.h" 16 #include "include/audit.h" 17 #include "include/cred.h" 18 #include "include/file.h" 19 #include "include/match.h" 20 #include "include/net.h" 21 #include "include/path.h" 22 #include "include/policy.h" 23 #include "include/label.h" 24 25 static u32 map_mask_to_chr_mask(u32 mask) 26 { 27 u32 m = mask & PERMS_CHRS_MASK; 28 29 if (mask & AA_MAY_GETATTR) 30 m |= MAY_READ; 31 if (mask & (AA_MAY_SETATTR | AA_MAY_CHMOD | AA_MAY_CHOWN)) 32 m |= MAY_WRITE; 33 34 return m; 35 } 36 37 /** 38 * file_audit_cb - call back for file specific audit fields 39 * @ab: audit_buffer (NOT NULL) 40 * @va: audit struct to audit values of (NOT NULL) 41 */ 42 static void file_audit_cb(struct audit_buffer *ab, void *va) 43 { 44 struct common_audit_data *sa = va; 45 kuid_t fsuid = current_fsuid(); 46 char str[10]; 47 48 if (aad(sa)->request & AA_AUDIT_FILE_MASK) { 49 aa_perm_mask_to_str(str, sizeof(str), aa_file_perm_chrs, 50 map_mask_to_chr_mask(aad(sa)->request)); 51 audit_log_format(ab, " requested_mask=\"%s\"", str); 52 } 53 if (aad(sa)->denied & AA_AUDIT_FILE_MASK) { 54 aa_perm_mask_to_str(str, sizeof(str), aa_file_perm_chrs, 55 map_mask_to_chr_mask(aad(sa)->denied)); 56 audit_log_format(ab, " denied_mask=\"%s\"", str); 57 } 58 if (aad(sa)->request & AA_AUDIT_FILE_MASK) { 59 audit_log_format(ab, " fsuid=%d", 60 from_kuid(&init_user_ns, fsuid)); 61 audit_log_format(ab, " ouid=%d", 62 from_kuid(&init_user_ns, aad(sa)->fs.ouid)); 63 } 64 65 if (aad(sa)->peer) { 66 audit_log_format(ab, " target="); 67 aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer, 68 FLAG_VIEW_SUBNS, GFP_KERNEL); 69 } else if (aad(sa)->fs.target) { 70 audit_log_format(ab, " target="); 71 audit_log_untrustedstring(ab, aad(sa)->fs.target); 72 } 73 } 74 75 /** 76 * aa_audit_file - handle the auditing of file operations 77 * @profile: the profile being enforced (NOT NULL) 78 * @perms: the permissions computed for the request (NOT NULL) 79 * @op: operation being mediated 80 * @request: permissions requested 81 * @name: name of object being mediated (MAYBE NULL) 82 * @target: name of target (MAYBE NULL) 83 * @tlabel: target label (MAY BE NULL) 84 * @ouid: object uid 85 * @info: extra information message (MAYBE NULL) 86 * @error: 0 if operation allowed else failure error code 87 * 88 * Returns: %0 or error on failure 89 */ 90 int aa_audit_file(struct aa_profile *profile, struct aa_perms *perms, 91 const char *op, u32 request, const char *name, 92 const char *target, struct aa_label *tlabel, 93 kuid_t ouid, const char *info, int error) 94 { 95 int type = AUDIT_APPARMOR_AUTO; 96 DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_TASK, op); 97 98 sa.u.tsk = NULL; 99 aad(&sa)->request = request; 100 aad(&sa)->name = name; 101 aad(&sa)->fs.target = target; 102 aad(&sa)->peer = tlabel; 103 aad(&sa)->fs.ouid = ouid; 104 aad(&sa)->info = info; 105 aad(&sa)->error = error; 106 sa.u.tsk = NULL; 107 108 if (likely(!aad(&sa)->error)) { 109 u32 mask = perms->audit; 110 111 if (unlikely(AUDIT_MODE(profile) == AUDIT_ALL)) 112 mask = 0xffff; 113 114 /* mask off perms that are not being force audited */ 115 aad(&sa)->request &= mask; 116 117 if (likely(!aad(&sa)->request)) 118 return 0; 119 type = AUDIT_APPARMOR_AUDIT; 120 } else { 121 /* only report permissions that were denied */ 122 aad(&sa)->request = aad(&sa)->request & ~perms->allow; 123 AA_BUG(!aad(&sa)->request); 124 125 if (aad(&sa)->request & perms->kill) 126 type = AUDIT_APPARMOR_KILL; 127 128 /* quiet known rejects, assumes quiet and kill do not overlap */ 129 if ((aad(&sa)->request & perms->quiet) && 130 AUDIT_MODE(profile) != AUDIT_NOQUIET && 131 AUDIT_MODE(profile) != AUDIT_ALL) 132 aad(&sa)->request &= ~perms->quiet; 133 134 if (!aad(&sa)->request) 135 return aad(&sa)->error; 136 } 137 138 aad(&sa)->denied = aad(&sa)->request & ~perms->allow; 139 return aa_audit(type, profile, &sa, file_audit_cb); 140 } 141 142 /** 143 * is_deleted - test if a file has been completely unlinked 144 * @dentry: dentry of file to test for deletion (NOT NULL) 145 * 146 * Returns: true if deleted else false 147 */ 148 static inline bool is_deleted(struct dentry *dentry) 149 { 150 if (d_unlinked(dentry) && d_backing_inode(dentry)->i_nlink == 0) 151 return true; 152 return false; 153 } 154 155 static int path_name(const char *op, struct aa_label *label, 156 const struct path *path, int flags, char *buffer, 157 const char **name, struct path_cond *cond, u32 request) 158 { 159 struct aa_profile *profile; 160 const char *info = NULL; 161 int error; 162 163 error = aa_path_name(path, flags, buffer, name, &info, 164 labels_profile(label)->disconnected); 165 if (error) { 166 fn_for_each_confined(label, profile, 167 aa_audit_file(profile, &nullperms, op, request, *name, 168 NULL, NULL, cond->uid, info, error)); 169 return error; 170 } 171 172 return 0; 173 } 174 175 /** 176 * map_old_perms - map old file perms layout to the new layout 177 * @old: permission set in old mapping 178 * 179 * Returns: new permission mapping 180 */ 181 static u32 map_old_perms(u32 old) 182 { 183 u32 new = old & 0xf; 184 if (old & MAY_READ) 185 new |= AA_MAY_GETATTR | AA_MAY_OPEN; 186 if (old & MAY_WRITE) 187 new |= AA_MAY_SETATTR | AA_MAY_CREATE | AA_MAY_DELETE | 188 AA_MAY_CHMOD | AA_MAY_CHOWN | AA_MAY_OPEN; 189 if (old & 0x10) 190 new |= AA_MAY_LINK; 191 /* the old mapping lock and link_subset flags where overlaid 192 * and use was determined by part of a pair that they were in 193 */ 194 if (old & 0x20) 195 new |= AA_MAY_LOCK | AA_LINK_SUBSET; 196 if (old & 0x40) /* AA_EXEC_MMAP */ 197 new |= AA_EXEC_MMAP; 198 199 return new; 200 } 201 202 /** 203 * aa_compute_fperms - convert dfa compressed perms to internal perms 204 * @dfa: dfa to compute perms for (NOT NULL) 205 * @state: state in dfa 206 * @cond: conditions to consider (NOT NULL) 207 * 208 * TODO: convert from dfa + state to permission entry, do computation conversion 209 * at load time. 210 * 211 * Returns: computed permission set 212 */ 213 struct aa_perms aa_compute_fperms(struct aa_dfa *dfa, unsigned int state, 214 struct path_cond *cond) 215 { 216 /* FIXME: change over to new dfa format 217 * currently file perms are encoded in the dfa, new format 218 * splits the permissions from the dfa. This mapping can be 219 * done at profile load 220 */ 221 struct aa_perms perms = { }; 222 223 if (uid_eq(current_fsuid(), cond->uid)) { 224 perms.allow = map_old_perms(dfa_user_allow(dfa, state)); 225 perms.audit = map_old_perms(dfa_user_audit(dfa, state)); 226 perms.quiet = map_old_perms(dfa_user_quiet(dfa, state)); 227 perms.xindex = dfa_user_xindex(dfa, state); 228 } else { 229 perms.allow = map_old_perms(dfa_other_allow(dfa, state)); 230 perms.audit = map_old_perms(dfa_other_audit(dfa, state)); 231 perms.quiet = map_old_perms(dfa_other_quiet(dfa, state)); 232 perms.xindex = dfa_other_xindex(dfa, state); 233 } 234 perms.allow |= AA_MAY_GETATTR; 235 236 /* change_profile wasn't determined by ownership in old mapping */ 237 if (ACCEPT_TABLE(dfa)[state] & 0x80000000) 238 perms.allow |= AA_MAY_CHANGE_PROFILE; 239 if (ACCEPT_TABLE(dfa)[state] & 0x40000000) 240 perms.allow |= AA_MAY_ONEXEC; 241 242 return perms; 243 } 244 245 /** 246 * aa_str_perms - find permission that match @name 247 * @dfa: to match against (MAYBE NULL) 248 * @state: state to start matching in 249 * @name: string to match against dfa (NOT NULL) 250 * @cond: conditions to consider for permission set computation (NOT NULL) 251 * @perms: Returns - the permissions found when matching @name 252 * 253 * Returns: the final state in @dfa when beginning @start and walking @name 254 */ 255 unsigned int aa_str_perms(struct aa_dfa *dfa, unsigned int start, 256 const char *name, struct path_cond *cond, 257 struct aa_perms *perms) 258 { 259 unsigned int state; 260 state = aa_dfa_match(dfa, start, name); 261 *perms = aa_compute_fperms(dfa, state, cond); 262 263 return state; 264 } 265 266 int __aa_path_perm(const char *op, struct aa_profile *profile, const char *name, 267 u32 request, struct path_cond *cond, int flags, 268 struct aa_perms *perms) 269 { 270 int e = 0; 271 272 if (profile_unconfined(profile)) 273 return 0; 274 aa_str_perms(profile->file.dfa, profile->file.start, name, cond, perms); 275 if (request & ~perms->allow) 276 e = -EACCES; 277 return aa_audit_file(profile, perms, op, request, name, NULL, NULL, 278 cond->uid, NULL, e); 279 } 280 281 282 static int profile_path_perm(const char *op, struct aa_profile *profile, 283 const struct path *path, char *buffer, u32 request, 284 struct path_cond *cond, int flags, 285 struct aa_perms *perms) 286 { 287 const char *name; 288 int error; 289 290 if (profile_unconfined(profile)) 291 return 0; 292 293 error = path_name(op, &profile->label, path, 294 flags | profile->path_flags, buffer, &name, cond, 295 request); 296 if (error) 297 return error; 298 return __aa_path_perm(op, profile, name, request, cond, flags, 299 perms); 300 } 301 302 /** 303 * aa_path_perm - do permissions check & audit for @path 304 * @op: operation being checked 305 * @label: profile being enforced (NOT NULL) 306 * @path: path to check permissions of (NOT NULL) 307 * @flags: any additional path flags beyond what the profile specifies 308 * @request: requested permissions 309 * @cond: conditional info for this request (NOT NULL) 310 * 311 * Returns: %0 else error if access denied or other error 312 */ 313 int aa_path_perm(const char *op, struct aa_label *label, 314 const struct path *path, int flags, u32 request, 315 struct path_cond *cond) 316 { 317 struct aa_perms perms = {}; 318 struct aa_profile *profile; 319 char *buffer = NULL; 320 int error; 321 322 flags |= PATH_DELEGATE_DELETED | (S_ISDIR(cond->mode) ? PATH_IS_DIR : 323 0); 324 buffer = aa_get_buffer(false); 325 if (!buffer) 326 return -ENOMEM; 327 error = fn_for_each_confined(label, profile, 328 profile_path_perm(op, profile, path, buffer, request, 329 cond, flags, &perms)); 330 331 aa_put_buffer(buffer); 332 333 return error; 334 } 335 336 /** 337 * xindex_is_subset - helper for aa_path_link 338 * @link: link permission set 339 * @target: target permission set 340 * 341 * test target x permissions are equal OR a subset of link x permissions 342 * this is done as part of the subset test, where a hardlink must have 343 * a subset of permissions that the target has. 344 * 345 * Returns: true if subset else false 346 */ 347 static inline bool xindex_is_subset(u32 link, u32 target) 348 { 349 if (((link & ~AA_X_UNSAFE) != (target & ~AA_X_UNSAFE)) || 350 ((link & AA_X_UNSAFE) && !(target & AA_X_UNSAFE))) 351 return false; 352 353 return true; 354 } 355 356 static int profile_path_link(struct aa_profile *profile, 357 const struct path *link, char *buffer, 358 const struct path *target, char *buffer2, 359 struct path_cond *cond) 360 { 361 const char *lname, *tname = NULL; 362 struct aa_perms lperms = {}, perms; 363 const char *info = NULL; 364 u32 request = AA_MAY_LINK; 365 unsigned int state; 366 int error; 367 368 error = path_name(OP_LINK, &profile->label, link, profile->path_flags, 369 buffer, &lname, cond, AA_MAY_LINK); 370 if (error) 371 goto audit; 372 373 /* buffer2 freed below, tname is pointer in buffer2 */ 374 error = path_name(OP_LINK, &profile->label, target, profile->path_flags, 375 buffer2, &tname, cond, AA_MAY_LINK); 376 if (error) 377 goto audit; 378 379 error = -EACCES; 380 /* aa_str_perms - handles the case of the dfa being NULL */ 381 state = aa_str_perms(profile->file.dfa, profile->file.start, lname, 382 cond, &lperms); 383 384 if (!(lperms.allow & AA_MAY_LINK)) 385 goto audit; 386 387 /* test to see if target can be paired with link */ 388 state = aa_dfa_null_transition(profile->file.dfa, state); 389 aa_str_perms(profile->file.dfa, state, tname, cond, &perms); 390 391 /* force audit/quiet masks for link are stored in the second entry 392 * in the link pair. 393 */ 394 lperms.audit = perms.audit; 395 lperms.quiet = perms.quiet; 396 lperms.kill = perms.kill; 397 398 if (!(perms.allow & AA_MAY_LINK)) { 399 info = "target restricted"; 400 lperms = perms; 401 goto audit; 402 } 403 404 /* done if link subset test is not required */ 405 if (!(perms.allow & AA_LINK_SUBSET)) 406 goto done_tests; 407 408 /* Do link perm subset test requiring allowed permission on link are 409 * a subset of the allowed permissions on target. 410 */ 411 aa_str_perms(profile->file.dfa, profile->file.start, tname, cond, 412 &perms); 413 414 /* AA_MAY_LINK is not considered in the subset test */ 415 request = lperms.allow & ~AA_MAY_LINK; 416 lperms.allow &= perms.allow | AA_MAY_LINK; 417 418 request |= AA_AUDIT_FILE_MASK & (lperms.allow & ~perms.allow); 419 if (request & ~lperms.allow) { 420 goto audit; 421 } else if ((lperms.allow & MAY_EXEC) && 422 !xindex_is_subset(lperms.xindex, perms.xindex)) { 423 lperms.allow &= ~MAY_EXEC; 424 request |= MAY_EXEC; 425 info = "link not subset of target"; 426 goto audit; 427 } 428 429 done_tests: 430 error = 0; 431 432 audit: 433 return aa_audit_file(profile, &lperms, OP_LINK, request, lname, tname, 434 NULL, cond->uid, info, error); 435 } 436 437 /** 438 * aa_path_link - Handle hard link permission check 439 * @label: the label being enforced (NOT NULL) 440 * @old_dentry: the target dentry (NOT NULL) 441 * @new_dir: directory the new link will be created in (NOT NULL) 442 * @new_dentry: the link being created (NOT NULL) 443 * 444 * Handle the permission test for a link & target pair. Permission 445 * is encoded as a pair where the link permission is determined 446 * first, and if allowed, the target is tested. The target test 447 * is done from the point of the link match (not start of DFA) 448 * making the target permission dependent on the link permission match. 449 * 450 * The subset test if required forces that permissions granted 451 * on link are a subset of the permission granted to target. 452 * 453 * Returns: %0 if allowed else error 454 */ 455 int aa_path_link(struct aa_label *label, struct dentry *old_dentry, 456 const struct path *new_dir, struct dentry *new_dentry) 457 { 458 struct path link = { .mnt = new_dir->mnt, .dentry = new_dentry }; 459 struct path target = { .mnt = new_dir->mnt, .dentry = old_dentry }; 460 struct path_cond cond = { 461 d_backing_inode(old_dentry)->i_uid, 462 d_backing_inode(old_dentry)->i_mode 463 }; 464 char *buffer = NULL, *buffer2 = NULL; 465 struct aa_profile *profile; 466 int error; 467 468 /* buffer freed below, lname is pointer in buffer */ 469 buffer = aa_get_buffer(false); 470 buffer2 = aa_get_buffer(false); 471 error = -ENOMEM; 472 if (!buffer || !buffer2) 473 goto out; 474 475 error = fn_for_each_confined(label, profile, 476 profile_path_link(profile, &link, buffer, &target, 477 buffer2, &cond)); 478 out: 479 aa_put_buffer(buffer); 480 aa_put_buffer(buffer2); 481 return error; 482 } 483 484 static void update_file_ctx(struct aa_file_ctx *fctx, struct aa_label *label, 485 u32 request) 486 { 487 struct aa_label *l, *old; 488 489 /* update caching of label on file_ctx */ 490 spin_lock(&fctx->lock); 491 old = rcu_dereference_protected(fctx->label, 492 lockdep_is_held(&fctx->lock)); 493 l = aa_label_merge(old, label, GFP_ATOMIC); 494 if (l) { 495 if (l != old) { 496 rcu_assign_pointer(fctx->label, l); 497 aa_put_label(old); 498 } else 499 aa_put_label(l); 500 fctx->allow |= request; 501 } 502 spin_unlock(&fctx->lock); 503 } 504 505 static int __file_path_perm(const char *op, struct aa_label *label, 506 struct aa_label *flabel, struct file *file, 507 u32 request, u32 denied, bool in_atomic) 508 { 509 struct aa_profile *profile; 510 struct aa_perms perms = {}; 511 struct path_cond cond = { 512 .uid = file_inode(file)->i_uid, 513 .mode = file_inode(file)->i_mode 514 }; 515 char *buffer; 516 int flags, error; 517 518 /* revalidation due to label out of date. No revocation at this time */ 519 if (!denied && aa_label_is_subset(flabel, label)) 520 /* TODO: check for revocation on stale profiles */ 521 return 0; 522 523 flags = PATH_DELEGATE_DELETED | (S_ISDIR(cond.mode) ? PATH_IS_DIR : 0); 524 buffer = aa_get_buffer(in_atomic); 525 if (!buffer) 526 return -ENOMEM; 527 528 /* check every profile in task label not in current cache */ 529 error = fn_for_each_not_in_set(flabel, label, profile, 530 profile_path_perm(op, profile, &file->f_path, buffer, 531 request, &cond, flags, &perms)); 532 if (denied && !error) { 533 /* 534 * check every profile in file label that was not tested 535 * in the initial check above. 536 * 537 * TODO: cache full perms so this only happens because of 538 * conditionals 539 * TODO: don't audit here 540 */ 541 if (label == flabel) 542 error = fn_for_each(label, profile, 543 profile_path_perm(op, profile, &file->f_path, 544 buffer, request, &cond, flags, 545 &perms)); 546 else 547 error = fn_for_each_not_in_set(label, flabel, profile, 548 profile_path_perm(op, profile, &file->f_path, 549 buffer, request, &cond, flags, 550 &perms)); 551 } 552 if (!error) 553 update_file_ctx(file_ctx(file), label, request); 554 555 aa_put_buffer(buffer); 556 557 return error; 558 } 559 560 static int __file_sock_perm(const char *op, struct aa_label *label, 561 struct aa_label *flabel, struct file *file, 562 u32 request, u32 denied) 563 { 564 struct socket *sock = (struct socket *) file->private_data; 565 int error; 566 567 AA_BUG(!sock); 568 569 /* revalidation due to label out of date. No revocation at this time */ 570 if (!denied && aa_label_is_subset(flabel, label)) 571 return 0; 572 573 /* TODO: improve to skip profiles cached in flabel */ 574 error = aa_sock_file_perm(label, op, request, sock); 575 if (denied) { 576 /* TODO: improve to skip profiles checked above */ 577 /* check every profile in file label to is cached */ 578 last_error(error, aa_sock_file_perm(flabel, op, request, sock)); 579 } 580 if (!error) 581 update_file_ctx(file_ctx(file), label, request); 582 583 return error; 584 } 585 586 /** 587 * aa_file_perm - do permission revalidation check & audit for @file 588 * @op: operation being checked 589 * @label: label being enforced (NOT NULL) 590 * @file: file to revalidate access permissions on (NOT NULL) 591 * @request: requested permissions 592 * @in_atomic: whether allocations need to be done in atomic context 593 * 594 * Returns: %0 if access allowed else error 595 */ 596 int aa_file_perm(const char *op, struct aa_label *label, struct file *file, 597 u32 request, bool in_atomic) 598 { 599 struct aa_file_ctx *fctx; 600 struct aa_label *flabel; 601 u32 denied; 602 int error = 0; 603 604 AA_BUG(!label); 605 AA_BUG(!file); 606 607 fctx = file_ctx(file); 608 609 rcu_read_lock(); 610 flabel = rcu_dereference(fctx->label); 611 AA_BUG(!flabel); 612 613 /* revalidate access, if task is unconfined, or the cached cred 614 * doesn't match or if the request is for more permissions than 615 * was granted. 616 * 617 * Note: the test for !unconfined(flabel) is to handle file 618 * delegation from unconfined tasks 619 */ 620 denied = request & ~fctx->allow; 621 if (unconfined(label) || unconfined(flabel) || 622 (!denied && aa_label_is_subset(flabel, label))) { 623 rcu_read_unlock(); 624 goto done; 625 } 626 627 flabel = aa_get_newest_label(flabel); 628 rcu_read_unlock(); 629 /* TODO: label cross check */ 630 631 if (file->f_path.mnt && path_mediated_fs(file->f_path.dentry)) 632 error = __file_path_perm(op, label, flabel, file, request, 633 denied, in_atomic); 634 635 else if (S_ISSOCK(file_inode(file)->i_mode)) 636 error = __file_sock_perm(op, label, flabel, file, request, 637 denied); 638 aa_put_label(flabel); 639 640 done: 641 return error; 642 } 643 644 static void revalidate_tty(struct aa_label *label) 645 { 646 struct tty_struct *tty; 647 int drop_tty = 0; 648 649 tty = get_current_tty(); 650 if (!tty) 651 return; 652 653 spin_lock(&tty->files_lock); 654 if (!list_empty(&tty->tty_files)) { 655 struct tty_file_private *file_priv; 656 struct file *file; 657 /* TODO: Revalidate access to controlling tty. */ 658 file_priv = list_first_entry(&tty->tty_files, 659 struct tty_file_private, list); 660 file = file_priv->file; 661 662 if (aa_file_perm(OP_INHERIT, label, file, MAY_READ | MAY_WRITE, 663 IN_ATOMIC)) 664 drop_tty = 1; 665 } 666 spin_unlock(&tty->files_lock); 667 tty_kref_put(tty); 668 669 if (drop_tty) 670 no_tty(); 671 } 672 673 static int match_file(const void *p, struct file *file, unsigned int fd) 674 { 675 struct aa_label *label = (struct aa_label *)p; 676 677 if (aa_file_perm(OP_INHERIT, label, file, aa_map_file_to_perms(file), 678 IN_ATOMIC)) 679 return fd + 1; 680 return 0; 681 } 682 683 684 /* based on selinux's flush_unauthorized_files */ 685 void aa_inherit_files(const struct cred *cred, struct files_struct *files) 686 { 687 struct aa_label *label = aa_get_newest_cred_label(cred); 688 struct file *devnull = NULL; 689 unsigned int n; 690 691 revalidate_tty(label); 692 693 /* Revalidate access to inherited open files. */ 694 n = iterate_fd(files, 0, match_file, label); 695 if (!n) /* none found? */ 696 goto out; 697 698 devnull = dentry_open(&aa_null, O_RDWR, cred); 699 if (IS_ERR(devnull)) 700 devnull = NULL; 701 /* replace all the matching ones with this */ 702 do { 703 replace_fd(n - 1, devnull, 0); 704 } while ((n = iterate_fd(files, n, match_file, label)) != 0); 705 if (devnull) 706 fput(devnull); 707 out: 708 aa_put_label(label); 709 } 710