diff options
| author | Stephen Smalley <sds@tycho.nsa.gov> | 2005-05-20 19:15:52 -0400 |
|---|---|---|
| committer | David Woodhouse <dwmw2@shinybook.infradead.org> | 2005-05-20 19:15:52 -0400 |
| commit | 011161051bbc25f7f8b7df059dbd934c534443f0 (patch) | |
| tree | f1ca3727e4130cacad86dfdae65e7533fcb67784 | |
| parent | fb19b4c6aa024837a0071f07baa07dbf49d07151 (diff) | |
AUDIT: Avoid sleeping function in SElinux AVC audit.
This patch changes the SELinux AVC to defer logging of paths to the audit
framework upon syscall exit, by saving a reference to the (dentry,vfsmount)
pair in an auxiliary audit item on the current audit context for processing
by audit_log_exit.
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: David Woodhouse <dwmw2@infradead.org>
| -rw-r--r-- | include/linux/audit.h | 3 | ||||
| -rw-r--r-- | kernel/auditsc.c | 40 | ||||
| -rw-r--r-- | security/selinux/avc.c | 17 |
3 files changed, 51 insertions, 9 deletions
diff --git a/include/linux/audit.h b/include/linux/audit.h index 17ea5d522d81..4b7caf0c6e10 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h | |||
| @@ -69,6 +69,7 @@ | |||
| 69 | 69 | ||
| 70 | #define AUDIT_AVC 1400 /* SE Linux avc denial or grant */ | 70 | #define AUDIT_AVC 1400 /* SE Linux avc denial or grant */ |
| 71 | #define AUDIT_SELINUX_ERR 1401 /* Internal SE Linux Errors */ | 71 | #define AUDIT_SELINUX_ERR 1401 /* Internal SE Linux Errors */ |
| 72 | #define AUDIT_AVC_PATH 1402 /* dentry, vfsmount pair from avc */ | ||
| 72 | 73 | ||
| 73 | #define AUDIT_KERNEL 2000 /* Asynchronous audit record. NOT A REQUEST. */ | 74 | #define AUDIT_KERNEL 2000 /* Asynchronous audit record. NOT A REQUEST. */ |
| 74 | 75 | ||
| @@ -225,6 +226,7 @@ extern uid_t audit_get_loginuid(struct audit_context *ctx); | |||
| 225 | extern int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode); | 226 | extern int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode); |
| 226 | extern int audit_socketcall(int nargs, unsigned long *args); | 227 | extern int audit_socketcall(int nargs, unsigned long *args); |
| 227 | extern int audit_sockaddr(int len, void *addr); | 228 | extern int audit_sockaddr(int len, void *addr); |
| 229 | extern int audit_avc_path(struct dentry *dentry, struct vfsmount *mnt); | ||
| 228 | extern void audit_signal_info(int sig, struct task_struct *t); | 230 | extern void audit_signal_info(int sig, struct task_struct *t); |
| 229 | #else | 231 | #else |
| 230 | #define audit_alloc(t) ({ 0; }) | 232 | #define audit_alloc(t) ({ 0; }) |
| @@ -240,6 +242,7 @@ extern void audit_signal_info(int sig, struct task_struct *t); | |||
| 240 | #define audit_ipc_perms(q,u,g,m) ({ 0; }) | 242 | #define audit_ipc_perms(q,u,g,m) ({ 0; }) |
| 241 | #define audit_socketcall(n,a) ({ 0; }) | 243 | #define audit_socketcall(n,a) ({ 0; }) |
| 242 | #define audit_sockaddr(len, addr) ({ 0; }) | 244 | #define audit_sockaddr(len, addr) ({ 0; }) |
| 245 | #define audit_avc_path(dentry, mnt) ({ 0; }) | ||
| 243 | #define audit_signal_info(s,t) do { ; } while (0) | 246 | #define audit_signal_info(s,t) do { ; } while (0) |
| 244 | #endif | 247 | #endif |
| 245 | 248 | ||
diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 78d7a13fc86f..8dc5b2767145 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c | |||
| @@ -34,6 +34,7 @@ | |||
| 34 | #include <asm/types.h> | 34 | #include <asm/types.h> |
| 35 | #include <linux/mm.h> | 35 | #include <linux/mm.h> |
| 36 | #include <linux/module.h> | 36 | #include <linux/module.h> |
| 37 | #include <linux/mount.h> | ||
| 37 | #include <linux/socket.h> | 38 | #include <linux/socket.h> |
| 38 | #include <linux/audit.h> | 39 | #include <linux/audit.h> |
| 39 | #include <linux/personality.h> | 40 | #include <linux/personality.h> |
| @@ -124,6 +125,11 @@ struct audit_aux_data_sockaddr { | |||
| 124 | char a[0]; | 125 | char a[0]; |
| 125 | }; | 126 | }; |
| 126 | 127 | ||
| 128 | struct audit_aux_data_path { | ||
| 129 | struct audit_aux_data d; | ||
| 130 | struct dentry *dentry; | ||
| 131 | struct vfsmount *mnt; | ||
| 132 | }; | ||
| 127 | 133 | ||
| 128 | /* The per-task audit context. */ | 134 | /* The per-task audit context. */ |
| 129 | struct audit_context { | 135 | struct audit_context { |
| @@ -553,6 +559,11 @@ static inline void audit_free_aux(struct audit_context *context) | |||
| 553 | struct audit_aux_data *aux; | 559 | struct audit_aux_data *aux; |
| 554 | 560 | ||
| 555 | while ((aux = context->aux)) { | 561 | while ((aux = context->aux)) { |
| 562 | if (aux->type == AUDIT_AVC_PATH) { | ||
| 563 | struct audit_aux_data_path *axi = (void *)aux; | ||
| 564 | dput(axi->dentry); | ||
| 565 | mntput(axi->mnt); | ||
| 566 | } | ||
| 556 | context->aux = aux->next; | 567 | context->aux = aux->next; |
| 557 | kfree(aux); | 568 | kfree(aux); |
| 558 | } | 569 | } |
| @@ -724,6 +735,14 @@ static void audit_log_exit(struct audit_context *context) | |||
| 724 | audit_log_format(ab, "saddr="); | 735 | audit_log_format(ab, "saddr="); |
| 725 | audit_log_hex(ab, axs->a, axs->len); | 736 | audit_log_hex(ab, axs->a, axs->len); |
| 726 | break; } | 737 | break; } |
| 738 | |||
| 739 | case AUDIT_AVC_PATH: { | ||
| 740 | struct audit_aux_data_path *axi = (void *)aux; | ||
| 741 | audit_log_d_path(ab, "path=", axi->dentry, axi->mnt); | ||
| 742 | dput(axi->dentry); | ||
| 743 | mntput(axi->mnt); | ||
| 744 | break; } | ||
| 745 | |||
| 727 | } | 746 | } |
| 728 | audit_log_end(ab); | 747 | audit_log_end(ab); |
| 729 | 748 | ||
| @@ -1124,6 +1143,27 @@ int audit_sockaddr(int len, void *a) | |||
| 1124 | return 0; | 1143 | return 0; |
| 1125 | } | 1144 | } |
| 1126 | 1145 | ||
| 1146 | int audit_avc_path(struct dentry *dentry, struct vfsmount *mnt) | ||
| 1147 | { | ||
| 1148 | struct audit_aux_data_path *ax; | ||
| 1149 | struct audit_context *context = current->audit_context; | ||
| 1150 | |||
| 1151 | if (likely(!context)) | ||
| 1152 | return 0; | ||
| 1153 | |||
| 1154 | ax = kmalloc(sizeof(*ax), GFP_ATOMIC); | ||
| 1155 | if (!ax) | ||
| 1156 | return -ENOMEM; | ||
| 1157 | |||
| 1158 | ax->dentry = dget(dentry); | ||
| 1159 | ax->mnt = mntget(mnt); | ||
| 1160 | |||
| 1161 | ax->d.type = AUDIT_AVC_PATH; | ||
| 1162 | ax->d.next = context->aux; | ||
| 1163 | context->aux = (void *)ax; | ||
| 1164 | return 0; | ||
| 1165 | } | ||
| 1166 | |||
| 1127 | void audit_signal_info(int sig, struct task_struct *t) | 1167 | void audit_signal_info(int sig, struct task_struct *t) |
| 1128 | { | 1168 | { |
| 1129 | extern pid_t audit_sig_pid; | 1169 | extern pid_t audit_sig_pid; |
diff --git a/security/selinux/avc.c b/security/selinux/avc.c index 62b963aca275..0fbc3e98c5ea 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c | |||
| @@ -573,13 +573,10 @@ void avc_audit(u32 ssid, u32 tsid, | |||
| 573 | case AVC_AUDIT_DATA_FS: | 573 | case AVC_AUDIT_DATA_FS: |
| 574 | if (a->u.fs.dentry) { | 574 | if (a->u.fs.dentry) { |
| 575 | struct dentry *dentry = a->u.fs.dentry; | 575 | struct dentry *dentry = a->u.fs.dentry; |
| 576 | if (a->u.fs.mnt) { | 576 | if (a->u.fs.mnt) |
| 577 | audit_log_d_path(ab, "path=", dentry, | 577 | audit_avc_path(dentry, a->u.fs.mnt); |
| 578 | a->u.fs.mnt); | 578 | audit_log_format(ab, " name=%s", |
| 579 | } else { | 579 | dentry->d_name.name); |
| 580 | audit_log_format(ab, " name=%s", | ||
| 581 | dentry->d_name.name); | ||
| 582 | } | ||
| 583 | inode = dentry->d_inode; | 580 | inode = dentry->d_inode; |
| 584 | } else if (a->u.fs.inode) { | 581 | } else if (a->u.fs.inode) { |
| 585 | struct dentry *dentry; | 582 | struct dentry *dentry; |
| @@ -630,8 +627,10 @@ void avc_audit(u32 ssid, u32 tsid, | |||
| 630 | case AF_UNIX: | 627 | case AF_UNIX: |
| 631 | u = unix_sk(sk); | 628 | u = unix_sk(sk); |
| 632 | if (u->dentry) { | 629 | if (u->dentry) { |
| 633 | audit_log_d_path(ab, "path=", | 630 | audit_avc_path(u->dentry, u->mnt); |
| 634 | u->dentry, u->mnt); | 631 | audit_log_format(ab, " name=%s", |
| 632 | u->dentry->d_name.name); | ||
| 633 | |||
| 635 | break; | 634 | break; |
| 636 | } | 635 | } |
| 637 | if (!u->addr) | 636 | if (!u->addr) |
