/* audit interface for capability */ void kse_cap_audit(struct task_struct *tsk, int cap, int result) { int sclass, request; struct common_audit_data ad; if (kse_noyaudit == 1 && result == 0) return; COMMON_AUDIT_DATA_INIT(&ad, CAP); ad.tsk = tsk; ad.u.cap = cap; request = CAP_TO_MASK(cap); switch (CAP_TO_INDEX(cap)) { case 0: sclass = SECCLASS_CAPABILITY; break; case 1: sclass = SECCLASS_CAPABILITY2; break; default: printk(KERN_ERR "KUXSE: out of range capability %d\n", cap); BUG(); } //kse_audit(task_cred_xxx(tsk, security), NULL, NULL, 0, sclass, //request, result, &ad); kse_audit(tsk->security, NULL, NULL, 0, sclass, request, result, &ad); }
/** * aa_info_message - log a none profile related status message * @str: message to log */ void aa_info_message(const char *str) { if (audit_enabled) { struct common_audit_data sa; COMMON_AUDIT_DATA_INIT(&sa, NONE); sa.aad.info = str; aa_audit_msg(AUDIT_APPARMOR_STATUS, &sa, NULL); } printk(KERN_INFO "AppArmor: %s\n", str); }
/** * aa_audit_ptrace - do auditing for ptrace * @profile: profile being enforced (NOT NULL) * @target: profile being traced (NOT NULL) * @error: error condition * * Returns: %0 or error code */ static int aa_audit_ptrace(struct aa_profile *profile, struct aa_profile *target, int error) { struct common_audit_data sa; COMMON_AUDIT_DATA_INIT(&sa, NONE); sa.aad.op = OP_PTRACE; sa.aad.target = target; sa.aad.error = error; return aa_audit(AUDIT_APPARMOR_AUTO, profile, GFP_ATOMIC, &sa, audit_cb); }
int aa_audit_file(struct aa_profile *profile, struct file_perms *perms, gfp_t gfp, int op, u32 request, const char *name, const char *target, uid_t ouid, const char *info, int error) { int type = AUDIT_APPARMOR_AUTO; struct common_audit_data sa; struct apparmor_audit_data aad = {0,}; COMMON_AUDIT_DATA_INIT(&sa, NONE); sa.aad = &aad; aad.op = op, aad.fs.request = request; aad.name = name; aad.fs.target = target; aad.fs.ouid = ouid; aad.info = info; aad.error = error; if (likely(!sa.aad->error)) { u32 mask = perms->audit; if (unlikely(AUDIT_MODE(profile) == AUDIT_ALL)) mask = 0xffff; /* */ sa.aad->fs.request &= mask; if (likely(!sa.aad->fs.request)) return 0; type = AUDIT_APPARMOR_AUDIT; } else { /* */ sa.aad->fs.request = sa.aad->fs.request & ~perms->allow; if (sa.aad->fs.request & perms->kill) type = AUDIT_APPARMOR_KILL; /* */ if ((sa.aad->fs.request & perms->quiet) && AUDIT_MODE(profile) != AUDIT_NOQUIET && AUDIT_MODE(profile) != AUDIT_ALL) sa.aad->fs.request &= ~perms->quiet; if (!sa.aad->fs.request) return COMPLAIN_MODE(profile) ? 0 : sa.aad->error; } sa.aad->fs.denied = sa.aad->fs.request & ~perms->allow; return aa_audit(type, profile, gfp, &sa, file_audit_cb); }
/** * aa_audit_file - handle the auditing of file operations * @profile: the profile being enforced (NOT NULL) * @perms: the permissions computed for the request (NOT NULL) * @gfp: allocation flags * @op: operation being mediated * @request: permissions requested * @name: name of object being mediated (MAYBE NULL) * @target: name of target (MAYBE NULL) * @ouid: object uid * @info: extra information message (MAYBE NULL) * @error: 0 if operation allowed else failure error code * * Returns: %0 or error on failure */ int aa_audit_file(struct aa_profile *profile, struct file_perms *perms, gfp_t gfp, int op, u32 request, const char *name, const char *target, uid_t ouid, const char *info, int error) { int type = AUDIT_APPARMOR_AUTO; struct common_audit_data sa; COMMON_AUDIT_DATA_INIT(&sa, NONE); sa.aad.op = op, sa.aad.fs.request = request; sa.aad.name = name; sa.aad.fs.target = target; sa.aad.fs.ouid = ouid; sa.aad.info = info; sa.aad.error = error; if (likely(!sa.aad.error)) { u32 mask = perms->audit; if (unlikely(AUDIT_MODE(profile) == AUDIT_ALL)) mask = 0xffff; /* mask off perms that are not being force audited */ sa.aad.fs.request &= mask; if (likely(!sa.aad.fs.request)) return 0; type = AUDIT_APPARMOR_AUDIT; } else { /* only report permissions that were denied */ sa.aad.fs.request = sa.aad.fs.request & ~perms->allow; if (sa.aad.fs.request & perms->kill) type = AUDIT_APPARMOR_KILL; /* quiet known rejects, assumes quiet and kill do not overlap */ if ((sa.aad.fs.request & perms->quiet) && AUDIT_MODE(profile) != AUDIT_NOQUIET && AUDIT_MODE(profile) != AUDIT_ALL) sa.aad.fs.request &= ~perms->quiet; if (!sa.aad.fs.request) return COMPLAIN_MODE(profile) ? 0 : sa.aad.error; } sa.aad.fs.denied = sa.aad.fs.request & ~perms->allow; return aa_audit(type, profile, gfp, &sa, file_audit_cb); }
/** * audit_caps - audit a capability * @profile: profile confining task (NOT NULL) * @task: task capability test was performed against (NOT NULL) * @cap: capability tested * @error: error code returned by test * * Do auditing of capability and handle, audit/complain/kill modes switching * and duplicate message elimination. * * Returns: 0 or sa->error on success, error code on failure */ static int audit_caps(struct aa_profile *profile, struct task_struct *task, int cap, int error) { struct audit_cache *ent; int type = AUDIT_APPARMOR_AUTO; struct common_audit_data sa; struct apparmor_audit_data aad = {0,}; COMMON_AUDIT_DATA_INIT(&sa, CAP); sa.aad = &aad; sa.tsk = task; sa.u.cap = cap; sa.aad->op = OP_CAPABLE; sa.aad->error = error; if (likely(!error)) { /* test if auditing is being forced */ if (likely((AUDIT_MODE(profile) != AUDIT_ALL) && !cap_raised(profile->caps.audit, cap))) return 0; type = AUDIT_APPARMOR_AUDIT; } else if (KILL_MODE(profile) || cap_raised(profile->caps.kill, cap)) { type = AUDIT_APPARMOR_KILL; } else if (cap_raised(profile->caps.quiet, cap) && AUDIT_MODE(profile) != AUDIT_NOQUIET && AUDIT_MODE(profile) != AUDIT_ALL) { /* quiet auditing */ return error; } /* Do simple duplicate message elimination */ ent = &get_cpu_var(audit_cache); if (profile == ent->profile && cap_raised(ent->caps, cap)) { put_cpu_var(audit_cache); if (COMPLAIN_MODE(profile)) return complain_error(error); return error; } else { aa_put_profile(ent->profile); ent->profile = aa_get_profile(profile); cap_raise(ent->caps, cap); } put_cpu_var(audit_cache); return aa_audit(type, profile, GFP_ATOMIC, &sa, audit_cb); }
/* * task_inode_perm: check permission when task operate on inode * tsk1: source task * inode: target inode * perm: permission to be checked * return value: * 0: granted * -1: denied * */ int task_inode_perm(struct task_struct *tsk1, struct inode *inode, struct dentry *dentry, int perm) { struct task_security_struct *tsp1; struct inode_security_struct *iss; struct common_audit_data ad; int ret; int request = 0; if (kse_enabled == 0) return 0; tsp1 = (struct task_security_struct *)task_cred_xxx(tsk1, security); iss = inode->i_security; COMMON_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.path.dentry = dentry; ad.u.fs.inode = inode; switch (perm) { case DIR__ADD_NAME: ret = kse_may_write(tsp1, NULL, iss, 1); break; case DIR__REMOVE_NAME: ret = kse_may_write(tsp1, NULL, iss, 1); break; case FILE__CREATE: ret = kse_may_write(tsp1, NULL, iss, 1); break; case FILE__LINK: ret = kse_may_write(tsp1, NULL, iss, 1); break; case FILE__UNLINK: ret = kse_may_write(tsp1, NULL, iss, 1); break; case FILE__READ: ret = kse_may_read(tsp1, NULL, iss, 1); break; case FILE__WRITE: ret = kse_may_write(tsp1, NULL, iss, 1); break; case FILE__APPEND: ret = kse_may_write(tsp1, NULL, iss, 1); break; case FILE__GETATTR: ret = kse_may_read(tsp1, NULL, iss, 1); break; case FILE__SETATTR: ret = kse_may_write(tsp1, NULL, iss, 1); break; case FILE__EXECUTE: ret = kse_may_read(tsp1, NULL, iss, 1); break; default: ret = -1; break; } request |= perm; if (kse_noyaudit == 1 && ret == 0) return ret; kse_audit(tsp1, NULL, iss, 1, SECCLASS_FILE, request, ret, &ad); return ret; }
/* * task_task_perm: check permission when task operate on task * tsk1: source task * tsk2: target task * perm: permission to be checked * return value: * 0: granted * -1: denied * */ int task_task_perm(struct task_struct *tsk1, struct task_struct *tsk2, int perm) { struct task_security_struct *tsp1; struct task_security_struct *tsp2; struct common_audit_data ad; int ret; int request = 0; if (kse_enabled == 0) return 0; if (tsk1 == NULL || tsk2 == NULL) return -1; tsp1 = (struct task_security_struct *)task_cred_xxx(tsk1, security); tsp2 = (struct task_security_struct *)task_cred_xxx(tsk2, security); if (tsp1 == NULL || tsp2 == NULL) return -1; COMMON_AUDIT_DATA_INIT(&ad, TASK); switch (perm) { case PROCESS__GETPGID: ret = kse_may_read(tsp1, tsp2, NULL, 0); break; case PROCESS__SETPGID: ret = kse_may_write(tsp1, tsp2, NULL, 0); break; case PROCESS__GETSESSION: ret = kse_may_read(tsp1, tsp2, NULL, 0); break; case PROCESS__GETATTR: ret = kse_may_read(tsp1, tsp2, NULL, 0); break; case PROCESS__GETSCHED: ret = kse_may_read(tsp1, tsp2, NULL, 0); break; case PROCESS__SETSCHED: ret = kse_may_write(tsp1, tsp2, NULL, 0); break; case PROCESS__SETRLIMIT: ret = kse_may_write(tsp1, tsp2, NULL, 0); break; case PROCESS__SIGNAL: ret = kse_may_write(tsp1, tsp2, NULL, 0); break; case PROCESS__SIGCHLD: ret = kse_may_write(tsp1, tsp2, NULL, 0); break; default: ret = -1; break; } request = perm; if (kse_noyaudit == 1 && ret == 0) return ret; kse_audit(tsp1, tsp2, NULL, 0, SECCLASS_PROCESS, request, ret, &ad); return ret; }