~ubuntu-branches/ubuntu/wily/apparmor/wily

« back to all changes in this revision

Viewing changes to module-deprecated/module_interface.c

  • Committer: Bazaar Package Importer
  • Author(s): Kees Cook
  • Date: 2011-04-27 10:38:07 UTC
  • mfrom: (5.1.118 natty)
  • Revision ID: james.westby@ubuntu.com-20110427103807-ym3rhwys6o84ith0
Tags: 2.6.1-2
debian/copyright: clarify for some full organization names.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 *      Copyright (C) 1998-2005 Novell/SUSE
3
 
 *
4
 
 *      This program is free software; you can redistribute it and/or
5
 
 *      modify it under the terms of the GNU General Public License as
6
 
 *      published by the Free Software Foundation, version 2 of the
7
 
 *      License.
8
 
 *
9
 
 *      AppArmor userspace policy interface
10
 
 */
11
 
 
12
 
#include <asm/unaligned.h>
13
 
 
14
 
#include "apparmor.h"
15
 
#include "inline.h"
16
 
#include "module_interface.h"
17
 
#include "aamatch/match.h"
18
 
 
19
 
/* sd_code defined in module_interface.h */
20
 
 
21
 
const int sdcode_datasize[] = { 1, 2, 4, 8, 2, 2, 4, 0, 0, 0, 0, 0, 0 };
22
 
 
23
 
struct sd_taskreplace_data {
24
 
        struct sdprofile *old_profile;
25
 
        struct sdprofile *new_profile;
26
 
};
27
 
 
28
 
/* inlines must be forward of there use in newer version of gcc,
29
 
   just forward declaring with a prototype won't work anymore */
30
 
 
31
 
static inline void free_sd_entry(struct sd_entry *entry)
32
 
{
33
 
        if (entry) {
34
 
                kfree(entry->filename);
35
 
                sdmatch_free(entry->extradata);
36
 
                kfree(entry);
37
 
        }
38
 
}
39
 
 
40
 
/**
41
 
 * alloc_sd_entry - create new empty sd_entry
42
 
 *
43
 
 * This routine allocates, initializes, and returns a new subdomain
44
 
 * file entry structure.  Structure is zeroed.  Returns new structure on
45
 
 * success, NULL on failure.
46
 
 */
47
 
static inline struct sd_entry *alloc_sd_entry(void)
48
 
{
49
 
        struct sd_entry *entry;
50
 
 
51
 
        SD_DEBUG("%s\n", __FUNCTION__);
52
 
        entry = kmalloc(sizeof(struct sd_entry), GFP_KERNEL);
53
 
        if (entry) {
54
 
                int i;
55
 
                memset(entry, 0, sizeof(struct sd_entry));
56
 
                INIT_LIST_HEAD(&entry->list);
57
 
                for (i = 0; i <= POS_SD_FILE_MAX; i++) {
58
 
                        INIT_LIST_HEAD(&entry->listp[i]);
59
 
                }
60
 
        }
61
 
        return entry;
62
 
}
63
 
 
64
 
/**
65
 
 * free_sdprofile - free sdprofile structure
66
 
 */
67
 
void free_sdprofile(struct sdprofile *profile)
68
 
{
69
 
        struct sd_entry *sdent, *tmp;
70
 
        struct sdprofile *p, *ptmp;
71
 
 
72
 
        SD_DEBUG("%s(%p)\n", __FUNCTION__, profile);
73
 
 
74
 
        if (!profile)
75
 
                return;
76
 
 
77
 
        /* profile is still on global profile list -- invalid */
78
 
        if (!list_empty(&profile->list)) {
79
 
                SD_ERROR("%s: internal error, "
80
 
                         "profile '%s' still on global list\n",
81
 
                         __FUNCTION__,
82
 
                         profile->name);
83
 
                BUG();
84
 
        }
85
 
 
86
 
        list_for_each_entry_safe(sdent, tmp, &profile->file_entry, list) {
87
 
                if (sdent->filename)
88
 
                        SD_DEBUG("freeing sd_entry: %p %s\n",
89
 
                                 sdent->filename, sdent->filename);
90
 
                list_del_init(&sdent->list);
91
 
                free_sd_entry(sdent);
92
 
        }
93
 
 
94
 
        list_for_each_entry_safe(p, ptmp, &profile->sub, list) {
95
 
                list_del_init(&p->list);
96
 
                put_sdprofile(p);
97
 
        }
98
 
 
99
 
        if (profile->name) {
100
 
                SD_DEBUG("%s: %s\n", __FUNCTION__, profile->name);
101
 
                kfree(profile->name);
102
 
        }
103
 
 
104
 
        kfree(profile);
105
 
}
106
 
 
107
 
/** task_remove
108
 
 *
109
 
 * remove profile in a task's subdomain leaving the task unconfined
110
 
 *
111
 
 * @sd: task's subdomain
112
 
 */
113
 
static inline void task_remove(struct subdomain *sd)
114
 
{
115
 
        /* write_lock(&sd_lock) held here */
116
 
        SD_DEBUG("%s: removing profile from task %s(%d) profile %s active %s\n",
117
 
                 __FUNCTION__,
118
 
                 sd->task->comm,
119
 
                 sd->task->pid,
120
 
                 sd->profile->name,
121
 
                 sd->active->name);
122
 
 
123
 
        sd_switch_unconfined(sd);
124
 
}
125
 
 
126
 
/** taskremove_iter
127
 
 *
128
 
 * Iterate over all subdomains.
129
 
 *
130
 
 * If any matches old_profile,  then call task_remove to remove it.
131
 
 * This leaves the task (subdomain) unconfined.
132
 
 */
133
 
static int taskremove_iter(struct subdomain *sd, void *cookie)
134
 
{
135
 
        struct sdprofile *old_profile = (struct sdprofile *)cookie;
136
 
        unsigned long flags;
137
 
 
138
 
        write_lock_irqsave(&sd_lock, flags);
139
 
 
140
 
        if (__sd_is_confined(sd) && sd->profile == old_profile)
141
 
                task_remove(sd);
142
 
 
143
 
        write_unlock_irqrestore(&sd_lock, flags);
144
 
 
145
 
        return 0;
146
 
}
147
 
 
148
 
/** task_replace
149
 
 *
150
 
 * replace profile in a task's subdomain with newly loaded profile
151
 
 *
152
 
 * @sd: task's subdomain
153
 
 * @new: old profile
154
 
 */
155
 
static inline void task_replace(struct subdomain *sd, struct sdprofile *new)
156
 
{
157
 
        struct sdprofile *nactive = NULL;
158
 
 
159
 
        SD_DEBUG("%s: replacing profile for task %s(%d) "
160
 
                 "profile=%s (%p) active=%s (%p)\n",
161
 
                 __FUNCTION__,
162
 
                 sd->task->comm, sd->task->pid,
163
 
                 sd->profile->name, sd->profile,
164
 
                 sd->active->name, sd->active);
165
 
 
166
 
        if (sd->profile == sd->active)
167
 
                nactive = get_sdprofile(new);
168
 
        else if (sd->active) {
169
 
                /* old in hat, new profile has hats */
170
 
                nactive = __sd_find_profile(sd->active->name, &new->sub);
171
 
 
172
 
                if (!nactive) {
173
 
                        if (new->flags.complain)
174
 
                                nactive = get_sdprofile(null_complain_profile);
175
 
                        else
176
 
                                nactive = get_sdprofile(null_profile);
177
 
                }
178
 
        }
179
 
        sd_switch(sd, new, nactive);
180
 
 
181
 
        put_sdprofile(nactive);
182
 
}
183
 
 
184
 
/** taskreplace_iter
185
 
 *
186
 
 * Iterate over all subdomains.
187
 
 *
188
 
 * If any matches old_profile,  then call task_replace to replace with
189
 
 * new_profile
190
 
 */
191
 
static int taskreplace_iter(struct subdomain *sd, void *cookie)
192
 
{
193
 
        struct sd_taskreplace_data *data = (struct sd_taskreplace_data *)cookie;
194
 
        unsigned long flags;
195
 
 
196
 
        write_lock_irqsave(&sd_lock, flags);
197
 
 
198
 
        if (__sd_is_confined(sd) && sd->profile == data->old_profile)
199
 
                task_replace(sd, data->new_profile);
200
 
 
201
 
        write_unlock_irqrestore(&sd_lock, flags);
202
 
 
203
 
        return 0;
204
 
}
205
 
 
206
 
static inline int sd_inbounds(struct sd_ext *e, size_t size)
207
 
{
208
 
        return (e->pos + size <= e->end);
209
 
}
210
 
 
211
 
/**
212
 
 * sdconvert - for codes that have a trailing value, convert that value
213
 
 *             and put it in dest.
214
 
 *             if a code does not have a trailing value nop
215
 
 * @code: type code
216
 
 * @dest: pointer to object to receive the converted value
217
 
 * @src:  pointer to value to convert
218
 
 */
219
 
static void sdconvert(enum sd_code code, void *dest, void *src)
220
 
{
221
 
        switch (code) {
222
 
        case SD_U8:
223
 
                *(u8 *)dest = *(u8 *) src;
224
 
                break;
225
 
        case SD_U16:
226
 
        case SD_NAME:
227
 
        case SD_DYN_STRING:
228
 
                *(u16 *)dest = le16_to_cpu(get_unaligned((u16 *)src));
229
 
                break;
230
 
        case SD_U32:
231
 
        case SD_STATIC_BLOB:
232
 
                *(u32 *)dest = le32_to_cpu(get_unaligned((u32 *)src));
233
 
                break;
234
 
        case SD_U64:
235
 
                *(u64 *)dest = le64_to_cpu(get_unaligned((u64 *)src));
236
 
                break;
237
 
        default:
238
 
                /* nop - all other type codes do not have a trailing value */
239
 
                ;
240
 
        }
241
 
}
242
 
 
243
 
/**
244
 
 * sd_is_X - check if the next element is of type X and if it is within
245
 
 *           bounds.  If it is put the associated value in data.
246
 
 * @e: extent information
247
 
 * @code: type code
248
 
 * @data: object located at @e->pos (of type @code) is written into @data
249
 
 *        if @data is non-null.  if data is null it means skip this
250
 
 *        entry
251
 
 * return the size of bytes associated with the returned data
252
 
 *        for complex object like blob and string a pointer to the allocated
253
 
 *        data is returned in data, but the size of the blob or string is
254
 
 *        returned.
255
 
 */
256
 
static u32 sd_is_X(struct sd_ext *e, enum sd_code code, void *data)
257
 
{
258
 
        void *pos = e->pos;
259
 
        int ret = 0;
260
 
        if (!sd_inbounds(e, SD_CODE_BYTE + sdcode_datasize[code]))
261
 
                goto fail;
262
 
        if (code != *(u8 *)e->pos)
263
 
                goto out;
264
 
        e->pos += SD_CODE_BYTE;
265
 
        if (code == SD_NAME) {
266
 
                u16 size;
267
 
                /* name codes are followed by X bytes */
268
 
                size = le16_to_cpu(get_unaligned((u16 *)e->pos));
269
 
                if (!sd_inbounds(e, (size_t) size))
270
 
                        goto fail;
271
 
                if (data)
272
 
                        *(u16 *)data = size;
273
 
                e->pos += sdcode_datasize[code];
274
 
                ret = 1 + sdcode_datasize[code];
275
 
        } else if (code == SD_DYN_STRING) {
276
 
                u16 size;
277
 
                char *str;
278
 
                /* strings codes are followed by X bytes */
279
 
                size = le16_to_cpu(get_unaligned((u16 *)e->pos));
280
 
                e->pos += sdcode_datasize[code];
281
 
                if (!sd_inbounds(e, (size_t) size))
282
 
                        goto fail;
283
 
                if (data) {
284
 
                        * (char **)data = NULL;
285
 
                        str = kmalloc(size, GFP_KERNEL);
286
 
                        if (!str)
287
 
                                goto fail;
288
 
                        memcpy(str, e->pos, (size_t) size);
289
 
                        str[size-1] = '\0';
290
 
                        * (char **)data = str;
291
 
                }
292
 
                e->pos += size;
293
 
                ret = size;
294
 
        } else if (code == SD_STATIC_BLOB) {
295
 
                u32 size;
296
 
                /* blobs are followed by X bytes, that can be 2^32 */
297
 
                size = le32_to_cpu(get_unaligned((u32 *)e->pos));
298
 
                e->pos += sdcode_datasize[code];
299
 
                if (!sd_inbounds(e, (size_t) size))
300
 
                        goto fail;
301
 
                if (data)
302
 
                        memcpy(data, e->pos, (size_t) size);
303
 
                e->pos += size;
304
 
                ret = size;
305
 
        } else {
306
 
                if (data)
307
 
                        sdconvert(code, data, e->pos);
308
 
                e->pos += sdcode_datasize[code];
309
 
                ret = 1 + sdcode_datasize[code];
310
 
        }
311
 
out:
312
 
        return ret;
313
 
fail:
314
 
        e->pos = pos;
315
 
        return 0;
316
 
}
317
 
 
318
 
/* sd_is_nameX - check is the next element is X, and its tag is name.
319
 
 * if the code matches and name (if specified) matches then the packed data
320
 
 * is unpacked into *data.  (Note for strings this is the size, and the next
321
 
 * data in the stream is the string data)
322
 
 * returns 0 if either match failes
323
 
 */
324
 
static int sd_is_nameX(struct sd_ext *e, enum sd_code code, void *data,
325
 
                       const char *name)
326
 
{
327
 
        void *pos = e->pos;
328
 
        u16 size;
329
 
        u32 ret;
330
 
        /* check for presence of a tagname, and if present name size
331
 
         * SD_NAME tag value is a u16 */
332
 
        if (sd_is_X(e, SD_NAME, &size)) {
333
 
                /* if a name is specified it must match. otherwise skip tag */
334
 
                if (name && ((strlen(name) != size-1) ||
335
 
                             strncmp(name, (char *)e->pos, (size_t)size-1)))
336
 
                        goto fail;
337
 
                e->pos += size;
338
 
        }
339
 
        /* now check if data actually matches */
340
 
        ret = sd_is_X(e, code, data);
341
 
        if (!ret)
342
 
                goto fail;
343
 
        return ret;
344
 
 
345
 
fail:
346
 
        e->pos = pos;
347
 
        return 0;
348
 
}
349
 
 
350
 
/* macro to wrap error case to make a block of reads look nicer */
351
 
#define SD_READ_X(E, C, D, N) \
352
 
        do { \
353
 
                u32 __ret; \
354
 
                __ret = sd_is_nameX((E), (C), (D), (N)); \
355
 
                if (!__ret) \
356
 
                        goto fail; \
357
 
        } while (0)
358
 
 
359
 
/**
360
 
 * sd_activate_net_entry - ignores/skips net entries if the they are present
361
 
 * in the data stream.
362
 
 * @e: extent information
363
 
 */
364
 
static inline int sd_activate_net_entry(struct sd_ext *e)
365
 
{
366
 
        SD_READ_X(e, SD_STRUCT, NULL, "ne");
367
 
        SD_READ_X(e, SD_U32, NULL, NULL);
368
 
        SD_READ_X(e, SD_U32, NULL, NULL);
369
 
        SD_READ_X(e, SD_U32, NULL, NULL);
370
 
        SD_READ_X(e, SD_U16, NULL, NULL);
371
 
        SD_READ_X(e, SD_U16, NULL, NULL);
372
 
        SD_READ_X(e, SD_U32, NULL, NULL);
373
 
        SD_READ_X(e, SD_U32, NULL, NULL);
374
 
        SD_READ_X(e, SD_U16, NULL, NULL);
375
 
        SD_READ_X(e, SD_U16, NULL, NULL);
376
 
        /* interface name is optional so just ignore return code */
377
 
        sd_is_nameX(e, SD_DYN_STRING, NULL, NULL);
378
 
        SD_READ_X(e, SD_STRUCTEND, NULL, NULL);
379
 
 
380
 
        return 1;
381
 
fail:
382
 
        return 0;
383
 
}
384
 
 
385
 
static inline struct sd_entry *sd_activate_file_entry(struct sd_ext *e)
386
 
{
387
 
        struct sd_entry *entry = NULL;
388
 
 
389
 
        if (!(entry = alloc_sd_entry()))
390
 
                goto fail;
391
 
 
392
 
        SD_READ_X(e, SD_STRUCT, NULL, "fe");
393
 
        SD_READ_X(e, SD_DYN_STRING, &entry->filename, NULL);
394
 
        SD_READ_X(e, SD_U32, &entry->mode, "file.mode");
395
 
        SD_READ_X(e, SD_U32, &entry->entry_type, "file.pattern_type");
396
 
 
397
 
        entry->extradata = sdmatch_alloc(entry->entry_type);
398
 
        if (IS_ERR(entry->extradata)) {
399
 
                entry->extradata = NULL;
400
 
                goto fail;
401
 
        }
402
 
 
403
 
        if (entry->extradata &&
404
 
            sdmatch_serialize(entry->extradata, e, sd_is_nameX) != 0) {
405
 
                goto fail;
406
 
        }
407
 
        SD_READ_X(e, SD_STRUCTEND, NULL, NULL);
408
 
 
409
 
        switch (entry->entry_type) {
410
 
        case sd_entry_literal:
411
 
                SD_DEBUG("%s: %s [no pattern] mode=0x%x\n",
412
 
                         __FUNCTION__,
413
 
                         entry->filename,
414
 
                         entry->mode);
415
 
                break;
416
 
        case sd_entry_tailglob:
417
 
                SD_DEBUG("%s: %s [tailglob] mode=0x%x\n",
418
 
                         __FUNCTION__,
419
 
                         entry->filename,
420
 
                         entry->mode);
421
 
                break;
422
 
        case sd_entry_pattern:
423
 
                SD_DEBUG("%s: %s mode=0x%x\n",
424
 
                         __FUNCTION__,
425
 
                         entry->filename,
426
 
                         entry->mode);
427
 
                break;
428
 
        default:
429
 
                SD_WARN("%s: INVALID entry_type %d\n",
430
 
                        __FUNCTION__,
431
 
                        (int)entry->entry_type);
432
 
                goto fail;
433
 
        }
434
 
 
435
 
        return entry;
436
 
 
437
 
fail:
438
 
        sdmatch_free(entry->extradata);
439
 
        free_sd_entry(entry);
440
 
        return NULL;
441
 
}
442
 
 
443
 
static inline int check_rule_and_add(struct sd_entry *file_entry,
444
 
                                     struct sdprofile *profile,
445
 
                                     const char **message)
446
 
{
447
 
        /* verify consistency of x, px, ix, ux for entry against
448
 
           possible duplicates for this entry */
449
 
        int mode = SD_EXEC_MODIFIER_MASK(file_entry->mode);
450
 
        int i;
451
 
 
452
 
        if (mode && !(SD_MAY_EXEC & file_entry->mode)) {
453
 
                *message = "inconsistent rule, x modifiers without x";
454
 
                goto out;
455
 
        }
456
 
 
457
 
        /* check that only 1 of the modifiers is set */
458
 
        if (mode && (mode & (mode - 1))) {
459
 
                *message = "inconsistent rule, multiple x modifiers";
460
 
                goto out;
461
 
        }
462
 
 
463
 
        /* ix -> m (required so that target exec binary may map itself) */
464
 
        if (mode & SD_EXEC_INHERIT)
465
 
                file_entry->mode |= SD_EXEC_MMAP;
466
 
 
467
 
        list_add(&file_entry->list, &profile->file_entry);
468
 
        profile->num_file_entries++;
469
 
 
470
 
        mode = file_entry->mode;
471
 
 
472
 
        /* Handle partitioned lists
473
 
         * Chain entries onto sublists based on individual
474
 
         * permission bits. This allows more rapid searching.
475
 
         */
476
 
        for (i = 0; i <= POS_SD_FILE_MAX; i++) {
477
 
                if (mode & (1 << i))
478
 
                        /* profile->file_entryp[i] initially set to
479
 
                         * NULL in alloc_sdprofile() */
480
 
                        list_add(&file_entry->listp[i],
481
 
                                 &profile->file_entryp[i]);
482
 
        }
483
 
 
484
 
        return 1;
485
 
 
486
 
out:
487
 
        free_sd_entry(file_entry);
488
 
        return 0;
489
 
}
490
 
 
491
 
#define SD_ENTRY_LIST(NAME) \
492
 
        do { \
493
 
        if (sd_is_nameX(e, SD_LIST, NULL, (NAME))) { \
494
 
                rulename = ""; \
495
 
                error_string = "Invalid file entry"; \
496
 
                while (!sd_is_nameX(e, SD_LISTEND, NULL, NULL)) { \
497
 
                        struct sd_entry *file_entry; \
498
 
                        file_entry = sd_activate_file_entry(e); \
499
 
                        if (!file_entry) \
500
 
                                goto fail; \
501
 
                        if (!check_rule_and_add(file_entry, profile, \
502
 
                                                &error_string)) { \
503
 
                                rulename = file_entry->filename; \
504
 
                                goto fail; \
505
 
                        } \
506
 
                } \
507
 
        } \
508
 
        } while (0)
509
 
 
510
 
struct sdprofile *sd_activate_profile(struct sd_ext *e, ssize_t *error)
511
 
{
512
 
        struct sdprofile *profile = NULL;
513
 
        const char *rulename = "";
514
 
        const char *error_string = "Invalid Profile";
515
 
 
516
 
        *error = -EPROTO;
517
 
 
518
 
        profile = alloc_sdprofile();
519
 
        if (!profile) {
520
 
                error_string = "Could not allocate profile";
521
 
                *error = -ENOMEM;
522
 
                goto fail;
523
 
        }
524
 
 
525
 
        /* check that we have the right struct being passed */
526
 
        SD_READ_X(e, SD_STRUCT, NULL, "profile");
527
 
        SD_READ_X(e, SD_DYN_STRING, &profile->name, NULL);
528
 
 
529
 
        error_string = "Invalid flags";
530
 
        /* per profile debug flags (debug, complain, audit) */
531
 
        SD_READ_X(e, SD_STRUCT, NULL, "flags");
532
 
        SD_READ_X(e, SD_U32, &(profile->flags.debug), "profile.flags.debug");
533
 
        SD_READ_X(e, SD_U32, &(profile->flags.complain),
534
 
                  "profile.flags.complain");
535
 
        SD_READ_X(e, SD_U32, &(profile->flags.audit), "profile.flags.audit");
536
 
        SD_READ_X(e, SD_STRUCTEND, NULL, NULL);
537
 
 
538
 
        error_string = "Invalid capabilities";
539
 
        SD_READ_X(e, SD_U32, &(profile->capabilities), "profile.capabilities");
540
 
 
541
 
        /* get the file entries. */
542
 
        SD_ENTRY_LIST("pgent");         /* pcre rules */
543
 
        SD_ENTRY_LIST("sgent");         /* simple globs */
544
 
        SD_ENTRY_LIST("fent");          /* regular file entries */
545
 
 
546
 
        /* get the net entries */
547
 
        if (sd_is_nameX(e, SD_LIST, NULL, "net")) {
548
 
                error_string = "Invalid net entry";
549
 
                while (!sd_is_nameX(e, SD_LISTEND, NULL, NULL)) {
550
 
                        if (!sd_activate_net_entry(e))
551
 
                                goto fail;
552
 
                }
553
 
        }
554
 
        rulename = "";
555
 
 
556
 
        /* get subprofiles */
557
 
        if (sd_is_nameX(e, SD_LIST, NULL, "hats")) {
558
 
                error_string = "Invalid profile hat";
559
 
                while (!sd_is_nameX(e, SD_LISTEND, NULL, NULL)) {
560
 
                        struct sdprofile *subprofile;
561
 
                        subprofile = sd_activate_profile(e, error);
562
 
                        if (!subprofile)
563
 
                                goto fail;
564
 
                        get_sdprofile(subprofile);
565
 
                        list_add(&subprofile->list, &profile->sub);
566
 
                }
567
 
        }
568
 
 
569
 
        error_string = "Invalid end of profile";
570
 
        SD_READ_X(e, SD_STRUCTEND, NULL, NULL);
571
 
 
572
 
        return profile;
573
 
 
574
 
fail:
575
 
        SD_WARN("%s: %s %s in profile %s\n", INTERFACE_ID, rulename,
576
 
                error_string, profile && profile->name ? profile->name
577
 
                : "unknown");
578
 
 
579
 
        if (profile) {
580
 
                free_sdprofile(profile);
581
 
                profile = NULL;
582
 
        }
583
 
 
584
 
        return NULL;
585
 
}
586
 
 
587
 
void *sd_activate_top_profile(struct sd_ext *e, ssize_t *error)
588
 
{
589
 
        /* get the interface version */
590
 
        if (!sd_is_nameX(e, SD_U32, &e->version, "version")) {
591
 
                SD_WARN("%s: version missing\n", INTERFACE_ID);
592
 
                *error = -EPROTONOSUPPORT;
593
 
                goto out;
594
 
        }
595
 
 
596
 
        /* check that the interface version is currently supported */
597
 
        if (e->version != 2) {
598
 
                SD_WARN("%s: unsupported interface version (%d)\n",
599
 
                        INTERFACE_ID, e->version);
600
 
                *error = -EPROTONOSUPPORT;
601
 
                goto out;
602
 
        }
603
 
 
604
 
        return sd_activate_profile(e, error);
605
 
out:
606
 
        return NULL;
607
 
}
608
 
 
609
 
ssize_t sd_file_prof_add(void *data, size_t size)
610
 
{
611
 
        struct sdprofile *profile = NULL;
612
 
 
613
 
        struct sd_ext e = { data, data + size, data };
614
 
        ssize_t error;
615
 
 
616
 
        profile = sd_activate_top_profile(&e, &error);
617
 
        if (!profile) {
618
 
                SD_DEBUG("couldn't activate profile\n");
619
 
                return error;
620
 
        }
621
 
 
622
 
        if (!sd_profilelist_add(profile)) {
623
 
                SD_WARN("trying to add profile (%s) that already exists.\n",
624
 
                        profile->name);
625
 
                free_sdprofile(profile);
626
 
                return -EEXIST;
627
 
        }
628
 
 
629
 
        return size;
630
 
}
631
 
 
632
 
ssize_t sd_file_prof_repl(void *udata, size_t size)
633
 
{
634
 
        struct sd_taskreplace_data data;
635
 
        struct sd_ext e = { udata, udata + size, udata };
636
 
        ssize_t error;
637
 
 
638
 
        data.new_profile = sd_activate_top_profile(&e, &error);
639
 
        if (!data.new_profile) {
640
 
                SD_DEBUG("couldn't activate profile\n");
641
 
                return error;
642
 
        }
643
 
        /* Grab reference to close race window (see comment below) */
644
 
        get_sdprofile(data.new_profile);
645
 
 
646
 
        /* Replace the profile on the global profile list.
647
 
         * This list is used by all new exec's to find the correct profile.
648
 
         * If there was a previous profile, it is returned, else NULL.
649
 
         *
650
 
         * N.B sd_profilelist_replace does not drop the refcnt on
651
 
         * old_profile when removing it from the global list, otherwise it
652
 
         * could reach zero and be automatically free'd. We nust manually
653
 
         * drop it at the end of this function when we are finished with it.
654
 
         */
655
 
        data.old_profile = sd_profilelist_replace(data.new_profile);
656
 
 
657
 
        /* RACE window here.
658
 
         * At this point another task could preempt us trying to replace
659
 
         * the SAME profile. If it makes it to this point,  it has removed
660
 
         * the original tasks new_profile from the global list and holds a
661
 
         * reference of 1 to it in it's old_profile.  If the new task
662
 
         * reaches the end of the function it will put old_profile causing
663
 
         * the profile to be deleted.
664
 
         * When the original task is rescheduled it will continue calling
665
 
         * sd_subdomainlist_iterate relabelling tasks with a profile
666
 
         * which points to free'd memory.
667
 
         */
668
 
 
669
 
        /* If there was an old profile,  find all currently executing tasks
670
 
         * using this profile and replace the old profile with the new.
671
 
         */
672
 
        if (data.old_profile) {
673
 
                SD_DEBUG("%s: try to replace profile (%p)%s\n",
674
 
                         __FUNCTION__,
675
 
                         data.old_profile,
676
 
                         data.old_profile->name);
677
 
 
678
 
                sd_subdomainlist_iterate(taskreplace_iter, (void *)&data);
679
 
 
680
 
                /* it's off global list, and we are done replacing */
681
 
                put_sdprofile(data.old_profile);
682
 
        }
683
 
 
684
 
        /* Free reference obtained above */
685
 
        put_sdprofile(data.new_profile);
686
 
 
687
 
        return size;
688
 
}
689
 
 
690
 
ssize_t sd_file_prof_remove(const char *name, size_t size)
691
 
{
692
 
        struct sdprofile *old_profile;
693
 
 
694
 
        /* if the old profile exists it will be removed from the list and
695
 
         * a reference is returned.
696
 
         */
697
 
        old_profile = sd_profilelist_remove(name);
698
 
 
699
 
        if (old_profile) {
700
 
                /* remove profile from any tasks using it */
701
 
                sd_subdomainlist_iterate(taskremove_iter, (void *)old_profile);
702
 
 
703
 
                /* drop reference obtained by sd_profilelist_remove */
704
 
                put_sdprofile(old_profile);
705
 
        } else {
706
 
                SD_WARN("%s: trying to remove profile (%s) that "
707
 
                        "doesn't exist - skipping.\n", __FUNCTION__, name);
708
 
                return -ENOENT;
709
 
        }
710
 
 
711
 
        return size;
712
 
}