📄 auditfilter.c
字号:
case AUDIT_ARG1: case AUDIT_ARG2: case AUDIT_ARG3: break; /* arch is only allowed to be = or != */ case AUDIT_ARCH: if ((f->op != AUDIT_NOT_EQUAL) && (f->op != AUDIT_EQUAL) && (f->op != AUDIT_NEGATE) && (f->op)) { err = -EINVAL; goto exit_free; } entry->rule.arch_f = f; break; case AUDIT_PERM: if (f->val & ~15) goto exit_free; break; case AUDIT_FILETYPE: if ((f->val & ~S_IFMT) > S_IFMT) goto exit_free; break; case AUDIT_INODE: err = audit_to_inode(&entry->rule, f); if (err) goto exit_free; break; } entry->rule.vers_ops = (f->op & AUDIT_OPERATORS) ? 2 : 1; /* Support for legacy operators where * AUDIT_NEGATE bit signifies != and otherwise assumes == */ if (f->op & AUDIT_NEGATE) f->op = AUDIT_NOT_EQUAL; else if (!f->op) f->op = AUDIT_EQUAL; else if (f->op == AUDIT_OPERATORS) { err = -EINVAL; goto exit_free; } } ino_f = entry->rule.inode_f; if (ino_f) { switch(ino_f->op) { case AUDIT_NOT_EQUAL: entry->rule.inode_f = NULL; case AUDIT_EQUAL: break; default: err = -EINVAL; goto exit_free; } }exit_nofree: return entry;exit_free: audit_free_rule(entry); return ERR_PTR(err);}/* Translate struct audit_rule_data to kernel's rule respresentation. */static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data, size_t datasz){ int err = 0; struct audit_entry *entry; struct audit_field *ino_f; void *bufp; size_t remain = datasz - sizeof(struct audit_rule_data); int i; char *str; entry = audit_to_entry_common((struct audit_rule *)data); if (IS_ERR(entry)) goto exit_nofree; bufp = data->buf; entry->rule.vers_ops = 2; for (i = 0; i < data->field_count; i++) { struct audit_field *f = &entry->rule.fields[i]; err = -EINVAL; if (!(data->fieldflags[i] & AUDIT_OPERATORS) || data->fieldflags[i] & ~AUDIT_OPERATORS) goto exit_free; f->op = data->fieldflags[i] & AUDIT_OPERATORS; f->type = data->fields[i]; f->val = data->values[i]; f->lsm_str = NULL; f->lsm_rule = NULL; switch(f->type) { case AUDIT_PID: case AUDIT_UID: case AUDIT_EUID: case AUDIT_SUID: case AUDIT_FSUID: case AUDIT_GID: case AUDIT_EGID: case AUDIT_SGID: case AUDIT_FSGID: case AUDIT_LOGINUID: case AUDIT_PERS: case AUDIT_MSGTYPE: case AUDIT_PPID: case AUDIT_DEVMAJOR: case AUDIT_DEVMINOR: case AUDIT_EXIT: case AUDIT_SUCCESS: case AUDIT_ARG0: case AUDIT_ARG1: case AUDIT_ARG2: case AUDIT_ARG3: break; case AUDIT_ARCH: entry->rule.arch_f = f; break; case AUDIT_SUBJ_USER: case AUDIT_SUBJ_ROLE: case AUDIT_SUBJ_TYPE: case AUDIT_SUBJ_SEN: case AUDIT_SUBJ_CLR: case AUDIT_OBJ_USER: case AUDIT_OBJ_ROLE: case AUDIT_OBJ_TYPE: case AUDIT_OBJ_LEV_LOW: case AUDIT_OBJ_LEV_HIGH: str = audit_unpack_string(&bufp, &remain, f->val); if (IS_ERR(str)) goto exit_free; entry->rule.buflen += f->val; err = security_audit_rule_init(f->type, f->op, str, (void **)&f->lsm_rule); /* Keep currently invalid fields around in case they * become valid after a policy reload. */ if (err == -EINVAL) { printk(KERN_WARNING "audit rule for LSM " "\'%s\' is invalid\n", str); err = 0; } if (err) { kfree(str); goto exit_free; } else f->lsm_str = str; break; case AUDIT_WATCH: str = audit_unpack_string(&bufp, &remain, f->val); if (IS_ERR(str)) goto exit_free; entry->rule.buflen += f->val; err = audit_to_watch(&entry->rule, str, f->val, f->op); if (err) { kfree(str); goto exit_free; } break; case AUDIT_DIR: str = audit_unpack_string(&bufp, &remain, f->val); if (IS_ERR(str)) goto exit_free; entry->rule.buflen += f->val; err = audit_make_tree(&entry->rule, str, f->op); kfree(str); if (err) goto exit_free; break; case AUDIT_INODE: err = audit_to_inode(&entry->rule, f); if (err) goto exit_free; break; case AUDIT_FILTERKEY: err = -EINVAL; if (entry->rule.filterkey || f->val > AUDIT_MAX_KEY_LEN) goto exit_free; str = audit_unpack_string(&bufp, &remain, f->val); if (IS_ERR(str)) goto exit_free; entry->rule.buflen += f->val; entry->rule.filterkey = str; break; case AUDIT_PERM: if (f->val & ~15) goto exit_free; break; case AUDIT_FILETYPE: if ((f->val & ~S_IFMT) > S_IFMT) goto exit_free; break; default: goto exit_free; } } ino_f = entry->rule.inode_f; if (ino_f) { switch(ino_f->op) { case AUDIT_NOT_EQUAL: entry->rule.inode_f = NULL; case AUDIT_EQUAL: break; default: err = -EINVAL; goto exit_free; } }exit_nofree: return entry;exit_free: audit_free_rule(entry); return ERR_PTR(err);}/* Pack a filter field's string representation into data block. */static inline size_t audit_pack_string(void **bufp, const char *str){ size_t len = strlen(str); memcpy(*bufp, str, len); *bufp += len; return len;}/* Translate kernel rule respresentation to struct audit_rule. * Exists for backward compatibility with userspace. */static struct audit_rule *audit_krule_to_rule(struct audit_krule *krule){ struct audit_rule *rule; int i; rule = kzalloc(sizeof(*rule), GFP_KERNEL); if (unlikely(!rule)) return NULL; rule->flags = krule->flags | krule->listnr; rule->action = krule->action; rule->field_count = krule->field_count; for (i = 0; i < rule->field_count; i++) { rule->values[i] = krule->fields[i].val; rule->fields[i] = krule->fields[i].type; if (krule->vers_ops == 1) { if (krule->fields[i].op & AUDIT_NOT_EQUAL) rule->fields[i] |= AUDIT_NEGATE; } else { rule->fields[i] |= krule->fields[i].op; } } for (i = 0; i < AUDIT_BITMASK_SIZE; i++) rule->mask[i] = krule->mask[i]; return rule;}/* Translate kernel rule respresentation to struct audit_rule_data. */static struct audit_rule_data *audit_krule_to_data(struct audit_krule *krule){ struct audit_rule_data *data; void *bufp; int i; data = kmalloc(sizeof(*data) + krule->buflen, GFP_KERNEL); if (unlikely(!data)) return NULL; memset(data, 0, sizeof(*data)); data->flags = krule->flags | krule->listnr; data->action = krule->action; data->field_count = krule->field_count; bufp = data->buf; for (i = 0; i < data->field_count; i++) { struct audit_field *f = &krule->fields[i]; data->fields[i] = f->type; data->fieldflags[i] = f->op; switch(f->type) { case AUDIT_SUBJ_USER: case AUDIT_SUBJ_ROLE: case AUDIT_SUBJ_TYPE: case AUDIT_SUBJ_SEN: case AUDIT_SUBJ_CLR: case AUDIT_OBJ_USER: case AUDIT_OBJ_ROLE: case AUDIT_OBJ_TYPE: case AUDIT_OBJ_LEV_LOW: case AUDIT_OBJ_LEV_HIGH: data->buflen += data->values[i] = audit_pack_string(&bufp, f->lsm_str); break; case AUDIT_WATCH: data->buflen += data->values[i] = audit_pack_string(&bufp, krule->watch->path); break; case AUDIT_DIR: data->buflen += data->values[i] = audit_pack_string(&bufp, audit_tree_path(krule->tree)); break; case AUDIT_FILTERKEY: data->buflen += data->values[i] = audit_pack_string(&bufp, krule->filterkey); break; default: data->values[i] = f->val; } } for (i = 0; i < AUDIT_BITMASK_SIZE; i++) data->mask[i] = krule->mask[i]; return data;}/* Compare two rules in kernel format. Considered success if rules * don't match. */static int audit_compare_rule(struct audit_krule *a, struct audit_krule *b){ int i; if (a->flags != b->flags || a->listnr != b->listnr || a->action != b->action || a->field_count != b->field_count) return 1; for (i = 0; i < a->field_count; i++) { if (a->fields[i].type != b->fields[i].type || a->fields[i].op != b->fields[i].op) return 1; switch(a->fields[i].type) { case AUDIT_SUBJ_USER: case AUDIT_SUBJ_ROLE: case AUDIT_SUBJ_TYPE: case AUDIT_SUBJ_SEN: case AUDIT_SUBJ_CLR: case AUDIT_OBJ_USER: case AUDIT_OBJ_ROLE: case AUDIT_OBJ_TYPE: case AUDIT_OBJ_LEV_LOW: case AUDIT_OBJ_LEV_HIGH: if (strcmp(a->fields[i].lsm_str, b->fields[i].lsm_str)) return 1; break; case AUDIT_WATCH: if (strcmp(a->watch->path, b->watch->path)) return 1; break; case AUDIT_DIR: if (strcmp(audit_tree_path(a->tree), audit_tree_path(b->tree))) return 1; break; case AUDIT_FILTERKEY: /* both filterkeys exist based on above type compare */ if (strcmp(a->filterkey, b->filterkey)) return 1; break; default: if (a->fields[i].val != b->fields[i].val) return 1; } } for (i = 0; i < AUDIT_BITMASK_SIZE; i++) if (a->mask[i] != b->mask[i]) return 1; return 0;}/* Duplicate the given audit watch. The new watch's rules list is initialized * to an empty list and wlist is undefined. */static struct audit_watch *audit_dupe_watch(struct audit_watch *old){ char *path; struct audit_watch *new; path = kstrdup(old->path, GFP_KERNEL); if (unlikely(!path)) return ERR_PTR(-ENOMEM); new = audit_init_watch(path); if (IS_ERR(new)) { kfree(path); goto out; } new->dev = old->dev; new->ino = old->ino; get_inotify_watch(&old->parent->wdata); new->parent = old->parent;out: return new;}/* Duplicate LSM field information. The lsm_rule is opaque, so must be * re-initialized. */static inline int audit_dupe_lsm_field(struct audit_field *df, struct audit_field *sf){ int ret = 0; char *lsm_str; /* our own copy of lsm_str */ lsm_str = kstrdup(sf->lsm_str, GFP_KERNEL); if (unlikely(!lsm_str)) return -ENOMEM; df->lsm_str = lsm_str; /* our own (refreshed) copy of lsm_rule */ ret = security_audit_rule_init(df->type, df->op, df->lsm_str, (void **)&df->lsm_rule); /* Keep currently invalid fields around in case they * become valid after a policy reload. */ if (ret == -EINVAL) { printk(KERN_WARNING "audit rule for LSM \'%s\' is " "invalid\n", df->lsm_str); ret = 0; } return ret;}/* Duplicate an audit rule. This will be a deep copy with the exception * of the watch - that pointer is carried over. The LSM specific fields * will be updated in the copy. The point is to be able to replace the old * rule with the new rule in the filterlist, then free the old rule. * The rlist element is undefined; list manipulations are handled apart from * the initial copy. */static struct audit_entry *audit_dupe_rule(struct audit_krule *old, struct audit_watch *watch){ u32 fcount = old->field_count; struct audit_entry *entry; struct audit_krule *new; char *fk; int i, err = 0; entry = audit_init_entry(fcount); if (unlikely(!entry)) return ERR_PTR(-ENOMEM); new = &entry->rule; new->vers_ops = old->vers_ops; new->flags = old->flags; new->listnr = old->listnr; new->action = old->action; for (i = 0; i < AUDIT_BITMASK_SIZE; i++) new->mask[i] = old->mask[i]; new->buflen = old->buflen; new->inode_f = old->inode_f; new->watch = NULL; new->field_count = old->field_count; /*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -