diff options
| -rw-r--r-- | kernel/audit.c | 5 | ||||
| -rw-r--r-- | kernel/auditsc.c | 95 |
2 files changed, 56 insertions, 44 deletions
diff --git a/kernel/audit.c b/kernel/audit.c index d321e251d32b..8376ec10cf24 100644 --- a/kernel/audit.c +++ b/kernel/audit.c | |||
| @@ -142,11 +142,6 @@ static void audit_set_pid(struct audit_buffer *ab, pid_t pid) | |||
| 142 | nlh->nlmsg_pid = pid; | 142 | nlh->nlmsg_pid = pid; |
| 143 | } | 143 | } |
| 144 | 144 | ||
| 145 | struct audit_entry { | ||
| 146 | struct list_head list; | ||
| 147 | struct audit_rule rule; | ||
| 148 | }; | ||
| 149 | |||
| 150 | static void audit_panic(const char *message) | 145 | static void audit_panic(const char *message) |
| 151 | { | 146 | { |
| 152 | switch (audit_failure) | 147 | switch (audit_failure) |
diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 818ef9fdab3c..488ba3dea8bb 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c | |||
| @@ -190,9 +190,36 @@ struct audit_entry { | |||
| 190 | 190 | ||
| 191 | extern int audit_pid; | 191 | extern int audit_pid; |
| 192 | 192 | ||
| 193 | /* Copy rule from user-space to kernel-space. Called from | ||
| 194 | * audit_add_rule during AUDIT_ADD. */ | ||
| 195 | static inline int audit_copy_rule(struct audit_rule *d, struct audit_rule *s) | ||
| 196 | { | ||
| 197 | int i; | ||
| 198 | |||
| 199 | if (s->action != AUDIT_NEVER | ||
| 200 | && s->action != AUDIT_POSSIBLE | ||
| 201 | && s->action != AUDIT_ALWAYS) | ||
| 202 | return -1; | ||
| 203 | if (s->field_count < 0 || s->field_count > AUDIT_MAX_FIELDS) | ||
| 204 | return -1; | ||
| 205 | if ((s->flags & ~AUDIT_FILTER_PREPEND) >= AUDIT_NR_FILTERS) | ||
| 206 | return -1; | ||
| 207 | |||
| 208 | d->flags = s->flags; | ||
| 209 | d->action = s->action; | ||
| 210 | d->field_count = s->field_count; | ||
| 211 | for (i = 0; i < d->field_count; i++) { | ||
| 212 | d->fields[i] = s->fields[i]; | ||
| 213 | d->values[i] = s->values[i]; | ||
| 214 | } | ||
| 215 | for (i = 0; i < AUDIT_BITMASK_SIZE; i++) d->mask[i] = s->mask[i]; | ||
| 216 | return 0; | ||
| 217 | } | ||
| 218 | |||
| 193 | /* Check to see if two rules are identical. It is called from | 219 | /* Check to see if two rules are identical. It is called from |
| 220 | * audit_add_rule during AUDIT_ADD and | ||
| 194 | * audit_del_rule during AUDIT_DEL. */ | 221 | * audit_del_rule during AUDIT_DEL. */ |
| 195 | static int audit_compare_rule(struct audit_rule *a, struct audit_rule *b) | 222 | static inline int audit_compare_rule(struct audit_rule *a, struct audit_rule *b) |
| 196 | { | 223 | { |
| 197 | int i; | 224 | int i; |
| 198 | 225 | ||
| @@ -221,18 +248,37 @@ static int audit_compare_rule(struct audit_rule *a, struct audit_rule *b) | |||
| 221 | /* Note that audit_add_rule and audit_del_rule are called via | 248 | /* Note that audit_add_rule and audit_del_rule are called via |
| 222 | * audit_receive() in audit.c, and are protected by | 249 | * audit_receive() in audit.c, and are protected by |
| 223 | * audit_netlink_sem. */ | 250 | * audit_netlink_sem. */ |
| 224 | static inline void audit_add_rule(struct audit_entry *entry, | 251 | static inline int audit_add_rule(struct audit_rule *rule, |
| 225 | struct list_head *list) | 252 | struct list_head *list) |
| 226 | { | 253 | { |
| 254 | struct audit_entry *entry; | ||
| 255 | |||
| 256 | /* Do not use the _rcu iterator here, since this is the only | ||
| 257 | * addition routine. */ | ||
| 258 | list_for_each_entry(entry, list, list) { | ||
| 259 | if (!audit_compare_rule(rule, &entry->rule)) { | ||
| 260 | return -EEXIST; | ||
| 261 | } | ||
| 262 | } | ||
| 263 | |||
| 264 | if (!(entry = kmalloc(sizeof(*entry), GFP_KERNEL))) | ||
| 265 | return -ENOMEM; | ||
| 266 | if (audit_copy_rule(&entry->rule, rule)) { | ||
| 267 | kfree(entry); | ||
| 268 | return -EINVAL; | ||
| 269 | } | ||
| 270 | |||
| 227 | if (entry->rule.flags & AUDIT_FILTER_PREPEND) { | 271 | if (entry->rule.flags & AUDIT_FILTER_PREPEND) { |
| 228 | entry->rule.flags &= ~AUDIT_FILTER_PREPEND; | 272 | entry->rule.flags &= ~AUDIT_FILTER_PREPEND; |
| 229 | list_add_rcu(&entry->list, list); | 273 | list_add_rcu(&entry->list, list); |
| 230 | } else { | 274 | } else { |
| 231 | list_add_tail_rcu(&entry->list, list); | 275 | list_add_tail_rcu(&entry->list, list); |
| 232 | } | 276 | } |
| 277 | |||
| 278 | return 0; | ||
| 233 | } | 279 | } |
| 234 | 280 | ||
| 235 | static void audit_free_rule(struct rcu_head *head) | 281 | static inline void audit_free_rule(struct rcu_head *head) |
| 236 | { | 282 | { |
| 237 | struct audit_entry *e = container_of(head, struct audit_entry, rcu); | 283 | struct audit_entry *e = container_of(head, struct audit_entry, rcu); |
| 238 | kfree(e); | 284 | kfree(e); |
| @@ -258,32 +304,6 @@ static inline int audit_del_rule(struct audit_rule *rule, | |||
| 258 | return -ENOENT; /* No matching rule */ | 304 | return -ENOENT; /* No matching rule */ |
| 259 | } | 305 | } |
| 260 | 306 | ||
| 261 | /* Copy rule from user-space to kernel-space. Called during | ||
| 262 | * AUDIT_ADD. */ | ||
| 263 | static int audit_copy_rule(struct audit_rule *d, struct audit_rule *s) | ||
| 264 | { | ||
| 265 | int i; | ||
| 266 | |||
| 267 | if (s->action != AUDIT_NEVER | ||
| 268 | && s->action != AUDIT_POSSIBLE | ||
| 269 | && s->action != AUDIT_ALWAYS) | ||
| 270 | return -1; | ||
| 271 | if (s->field_count < 0 || s->field_count > AUDIT_MAX_FIELDS) | ||
| 272 | return -1; | ||
| 273 | if ((s->flags & ~AUDIT_FILTER_PREPEND) >= AUDIT_NR_FILTERS) | ||
| 274 | return -1; | ||
| 275 | |||
| 276 | d->flags = s->flags; | ||
| 277 | d->action = s->action; | ||
| 278 | d->field_count = s->field_count; | ||
| 279 | for (i = 0; i < d->field_count; i++) { | ||
| 280 | d->fields[i] = s->fields[i]; | ||
| 281 | d->values[i] = s->values[i]; | ||
| 282 | } | ||
| 283 | for (i = 0; i < AUDIT_BITMASK_SIZE; i++) d->mask[i] = s->mask[i]; | ||
| 284 | return 0; | ||
| 285 | } | ||
| 286 | |||
| 287 | static int audit_list_rules(void *_dest) | 307 | static int audit_list_rules(void *_dest) |
| 288 | { | 308 | { |
| 289 | int pid, seq; | 309 | int pid, seq; |
| @@ -313,7 +333,6 @@ static int audit_list_rules(void *_dest) | |||
| 313 | int audit_receive_filter(int type, int pid, int uid, int seq, void *data, | 333 | int audit_receive_filter(int type, int pid, int uid, int seq, void *data, |
| 314 | uid_t loginuid) | 334 | uid_t loginuid) |
| 315 | { | 335 | { |
| 316 | struct audit_entry *entry; | ||
| 317 | struct task_struct *tsk; | 336 | struct task_struct *tsk; |
| 318 | int *dest; | 337 | int *dest; |
| 319 | int err = 0; | 338 | int err = 0; |
| @@ -340,16 +359,14 @@ int audit_receive_filter(int type, int pid, int uid, int seq, void *data, | |||
| 340 | } | 359 | } |
| 341 | break; | 360 | break; |
| 342 | case AUDIT_ADD: | 361 | case AUDIT_ADD: |
| 343 | if (!(entry = kmalloc(sizeof(*entry), GFP_KERNEL))) | 362 | listnr =((struct audit_rule *)data)->flags & ~AUDIT_FILTER_PREPEND; |
| 344 | return -ENOMEM; | 363 | if (listnr >= AUDIT_NR_FILTERS) |
| 345 | if (audit_copy_rule(&entry->rule, data)) { | ||
| 346 | kfree(entry); | ||
| 347 | return -EINVAL; | 364 | return -EINVAL; |
| 348 | } | 365 | |
| 349 | listnr = entry->rule.flags & ~AUDIT_FILTER_PREPEND; | 366 | err = audit_add_rule(data, &audit_filter_list[listnr]); |
| 350 | audit_add_rule(entry, &audit_filter_list[listnr]); | 367 | if (!err) |
| 351 | audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE, | 368 | audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE, |
| 352 | "auid=%u added an audit rule\n", loginuid); | 369 | "auid=%u added an audit rule\n", loginuid); |
| 353 | break; | 370 | break; |
| 354 | case AUDIT_DEL: | 371 | case AUDIT_DEL: |
| 355 | listnr =((struct audit_rule *)data)->flags & ~AUDIT_FILTER_PREPEND; | 372 | listnr =((struct audit_rule *)data)->flags & ~AUDIT_FILTER_PREPEND; |
