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

« back to all changes in this revision

Viewing changes to libraries/libapparmor/src/kernel_interface.c

  • Committer: Bazaar Package Importer
  • Author(s): Kees Cook
  • Date: 2011-08-10 18:12:34 UTC
  • mto: This revision was merged to the branch mainline in revision 9.
  • Revision ID: james.westby@ubuntu.com-20110810181234-b6obckg60cp99crg
Tags: upstream-2.7.0~beta1+bzr1774
ImportĀ upstreamĀ versionĀ 2.7.0~beta1+bzr1774

Show diffs side-by-side

added added

removed removed

Lines of Context:
22
22
#include <sys/types.h>
23
23
#include <sys/stat.h>
24
24
#include <sys/syscall.h>
 
25
#include <sys/socket.h>
25
26
#include <fcntl.h>
26
27
#include <errno.h>
27
28
#include <limits.h>
28
29
#include <stdarg.h>
 
30
#include <mntent.h>
 
31
 
 
32
#include "apparmor.h"
 
33
 
 
34
/* some non-Linux systems do not define a static value */
 
35
#ifndef PATH_MAX
 
36
# define PATH_MAX 4096
 
37
#endif
29
38
 
30
39
#define symbol_version(real, name, version) \
31
40
                __asm__ (".symver " #real "," #name "@" #version)
32
41
#define default_symbol_version(real, name, version) \
33
42
                __asm__ (".symver " #real "," #name "@@" #version)
34
43
 
35
 
static int setprocattr(const char *path, const char *buf, int len)
36
 
{
37
 
        int rc = -1;
38
 
        int fd, ret, ctlerr = 0;
 
44
/**
 
45
 * aa_find_mountpoint - find where the apparmor interface filesystem is mounted
 
46
 * @mnt: returns buffer with the mountpoint string
 
47
 *
 
48
 * Returns: 0 on success else -1 on error
 
49
 *
 
50
 * NOTE: this function only supports versions of apparmor using securityfs
 
51
 */
 
52
int aa_find_mountpoint(char **mnt)
 
53
{
 
54
        struct stat statbuf;
 
55
        struct mntent *mntpt;
 
56
        FILE *mntfile;
 
57
        int rc = -1;
 
58
 
 
59
        if (!mnt) {
 
60
                errno = EINVAL;
 
61
                return -1;
 
62
        }
 
63
 
 
64
        mntfile = setmntent("/proc/mounts", "r");
 
65
        if (!mntfile)
 
66
                return -1;
 
67
 
 
68
        while ((mntpt = getmntent(mntfile))) {
 
69
                char *proposed = NULL;
 
70
                if (strcmp(mntpt->mnt_type, "securityfs") != 0)
 
71
                        continue;
 
72
 
 
73
                if (asprintf(&proposed, "%s/apparmor", mntpt->mnt_dir) < 0)
 
74
                        /* ENOMEM */
 
75
                        break;
 
76
 
 
77
                if (stat(proposed, &statbuf) == 0) {
 
78
                        *mnt = proposed;
 
79
                        rc = 0;
 
80
                        break;
 
81
                }
 
82
                free(proposed);
 
83
        }
 
84
        endmntent(mntfile);
 
85
        if (rc == -1)
 
86
                errno = ENOENT;
 
87
        return rc;
 
88
}
 
89
 
 
90
/**
 
91
 * aa_is_enabled - determine if apparmor is enabled
 
92
 *
 
93
 * Returns: 1 if enabled else reason it is not, or 0 on error
 
94
 *
 
95
 * ENOSYS - no indication apparmor is present in the system
 
96
 * ENOENT - enabled but interface could not be found
 
97
 * ECANCELED - disabled at boot
 
98
 * ENOMEM - out of memory
 
99
 */
 
100
int aa_is_enabled(void)
 
101
{
 
102
        int serrno, fd, rc, size;
 
103
        char buffer[2];
 
104
        char *mnt;
 
105
 
 
106
        /* if the interface mountpoint is available apparmor is enabled */
 
107
        rc = aa_find_mountpoint(&mnt);
 
108
        if (rc == 0) {
 
109
                free(mnt);
 
110
                return 1;
 
111
        }
 
112
 
 
113
        /* determine why the interface mountpoint isn't available */
 
114
        fd = open("/sys/module/apparmor/parameters/enabled", O_RDONLY);
 
115
        if (fd == -1) {
 
116
                if (errno == ENOENT)
 
117
                        errno = ENOSYS;
 
118
                return 0;
 
119
        }
 
120
 
 
121
        size = read(fd, &buffer, 2);
 
122
        serrno = errno;
 
123
        close(fd);
 
124
        errno = serrno;
 
125
 
 
126
        if (size > 0) {
 
127
                if (buffer[0] == 'Y')
 
128
                        errno = ENOENT;
 
129
                else
 
130
                        errno = ECANCELED;
 
131
        }
 
132
        return 0;
 
133
}
 
134
 
 
135
static inline pid_t aa_gettid(void)
 
136
{
 
137
#ifdef SYS_gettid
 
138
        return syscall(SYS_gettid);
 
139
#else
 
140
        return getpid();
 
141
#endif
 
142
}
 
143
 
 
144
static char *procattr_path(pid_t pid, const char *attr)
 
145
{
 
146
        char *path = NULL;
 
147
        if (asprintf(&path, "/proc/%d/attr/%s", pid, attr) > 0)
 
148
                return path;
 
149
        return NULL;
 
150
}
 
151
 
 
152
/**
 
153
 * aa_getprocattr_raw - get the contents of @attr for @tid into @buf
 
154
 * @tid: tid of task to query
 
155
 * @attr: which /proc/<tid>/attr/<attr> to query
 
156
 * @buf: buffer to store the result in
 
157
 * @len: size of the buffer
 
158
 * @mode: if set will point to mode string within buffer if it is present
 
159
 *
 
160
 * Returns: size of data read or -1 on error, and sets errno
 
161
 */
 
162
int aa_getprocattr_raw(pid_t tid, const char *attr, char *buf, int len,
 
163
                       char **mode)
 
164
{
 
165
        int rc = -1;
 
166
        int fd, ret;
 
167
        char *tmp = NULL;
 
168
        int size = 0;
 
169
 
 
170
        if (!buf || len <= 0) {
 
171
                errno = EINVAL;
 
172
                goto out;
 
173
        }
 
174
 
 
175
        tmp = procattr_path(tid, attr);
 
176
        if (!tmp)
 
177
                goto out;
 
178
 
 
179
        fd = open(tmp, O_RDONLY);
 
180
        free(tmp);
 
181
        if (fd == -1) {
 
182
                goto out;
 
183
        }
 
184
 
 
185
        tmp = buf;
 
186
        do {
 
187
                ret = read(fd, tmp, len);
 
188
                if (ret <= 0)
 
189
                        break;
 
190
                tmp += ret;
 
191
                size += ret;
 
192
                len -= ret;
 
193
                if (len < 0) {
 
194
                        errno = ERANGE;
 
195
                        goto out2;
 
196
                }
 
197
        } while (ret > 0);
 
198
 
 
199
        if (ret < 0) {
 
200
                int saved;
 
201
                if (ret != -1) {
 
202
                        errno = EPROTO;
 
203
                }
 
204
                saved = errno;
 
205
                (void)close(fd);
 
206
                errno = saved;
 
207
                goto out;
 
208
        } else if (size > 0 && buf[size - 1] != 0) {
 
209
                /* check for null termination */
 
210
                if (buf[size - 1] == '\n') {
 
211
                        buf[size - 1] = 0;
 
212
                } else if (len == 0) {
 
213
                        errno = ERANGE;
 
214
                        goto out2;
 
215
                } else {
 
216
                        buf[size] = 0;
 
217
                        size++;
 
218
                }
 
219
 
 
220
                /*
 
221
                 * now separate the mode.  If we don't find it just
 
222
                 * return NULL
 
223
                 */
 
224
                if (mode)
 
225
                        *mode = NULL;
 
226
                if (strcmp(buf, "unconfined") != 0 &&
 
227
                    size > 4 && buf[size - 2] == ')') {
 
228
                        int pos = size - 3;
 
229
                        while (pos > 0 &&
 
230
                               !(buf[pos] == ' ' && buf[pos + 1] == '('))
 
231
                                pos--;
 
232
                        if (pos > 0) {
 
233
                                buf[pos] = 0; /* overwrite ' ' */
 
234
                                buf[size - 2] = 0; /* overwrite trailing ) */
 
235
                                if (mode)
 
236
                                        *mode = &buf[pos + 2]; /* skip '(' */
 
237
                        }
 
238
                }
 
239
        }
 
240
        rc = size;
 
241
 
 
242
out2:
 
243
        (void)close(fd);
 
244
out:
 
245
        return rc;
 
246
}
 
247
 
 
248
#define INITIAL_GUESS_SIZE 128
 
249
 
 
250
/**
 
251
 * aa_getprocattr - get the contents of @attr for @tid into @buf
 
252
 * @tid: tid of task to query
 
253
 * @attr: which /proc/<tid>/attr/<attr> to query
 
254
 * @buf: allocated buffer the result is stored in
 
255
 * @mode: if set will point to mode string within buffer if it is present
 
256
 *
 
257
 * Returns: size of data read or -1 on error, and sets errno
 
258
 */
 
259
int aa_getprocattr(pid_t tid, const char *attr, char **buf, char **mode)
 
260
{
 
261
        int rc, size = INITIAL_GUESS_SIZE/2;
 
262
        char *buffer = NULL;
 
263
 
 
264
        if (!buf) {
 
265
                errno = EINVAL;
 
266
                return -1;
 
267
        }
 
268
 
 
269
        do {
 
270
                size <<= 1;
 
271
                buffer = realloc(buffer, size);
 
272
                if (!buffer)
 
273
                        return -1;
 
274
                memset(buffer, 0, size);
 
275
 
 
276
                rc = aa_getprocattr_raw(tid, attr, buffer, size, mode);
 
277
        } while (rc == -1 && errno == ERANGE);
 
278
 
 
279
        if (rc == -1) {
 
280
                free(buffer);
 
281
                size = -1;
 
282
        } else
 
283
                *buf = buffer;
 
284
 
 
285
        return size;
 
286
}
 
287
 
 
288
static int setprocattr(pid_t tid, const char *attr, const char *buf, int len)
 
289
{
 
290
        int rc = -1;
 
291
        int fd, ret;
39
292
        char *ctl = NULL;
40
 
        pid_t tid = syscall(SYS_gettid);
41
293
 
42
294
        if (!buf) {
43
295
                errno = EINVAL;
44
296
                goto out;
45
297
        }
46
298
 
47
 
        ctlerr = asprintf(&ctl, path, tid);
48
 
        if (ctlerr < 0) {
 
299
        ctl = procattr_path(tid, attr);
 
300
        if (!ctl)
49
301
                goto out;
50
 
        }
51
302
 
52
303
        fd = open(ctl, O_WRONLY);
53
304
        if (fd == -1) {
99
350
                goto out;
100
351
        }
101
352
 
102
 
        rc = setprocattr("/proc/%d/attr/current", buf, len);
 
353
        rc = setprocattr(aa_gettid(), "current", buf, len);
103
354
out:
104
355
        if (buf) {
105
356
                /* clear local copy of magic token before freeing */
130
381
        if (len < 0)
131
382
                return -1;
132
383
 
133
 
        rc = setprocattr("/proc/%d/attr/current", buf, len);
 
384
        rc = setprocattr(aa_gettid(), "current", buf, len);
134
385
 
135
386
        free(buf);
136
387
        return rc;
151
402
        if (len < 0)
152
403
                return -1;
153
404
 
154
 
        rc = setprocattr("/proc/%d/attr/exec", buf, len);
 
405
        rc = setprocattr(aa_gettid(), "exec", buf, len);
155
406
 
156
407
        free(buf);
157
408
        return rc;
212
463
                /* step pos past trailing \0 */
213
464
                pos++;
214
465
 
215
 
        rc = setprocattr("/proc/%d/attr/current", buf, pos - buf);
 
466
        rc = setprocattr(aa_gettid(), "current", buf, pos - buf);
216
467
 
217
468
out:
218
469
        if (buf) {
251
502
        va_end(ap);
252
503
        return aa_change_hatv(argv, token);
253
504
}
 
505
 
 
506
/**
 
507
 * aa_gettaskcon - get the confinement for task @target in an allocated buffer
 
508
 * @target: task to query
 
509
 * @con: pointer to returned buffer with the confinement string
 
510
 * @mode: if provided will point to the mode string in @con if present
 
511
 *
 
512
 * Returns: length of confinement data or -1 on error and sets errno
 
513
 *
 
514
 * Guarentees that @con and @mode are null terminated.  The length returned
 
515
 * is for all data including both @con and @mode, and maybe > than strlen(@con)
 
516
 * even if @mode is NULL
 
517
 *
 
518
 * Caller is responsible for freeing the buffer returned in @con.  @mode is
 
519
 * always contained within @con's buffer and so NEVER do free(@mode)
 
520
 */
 
521
int aa_gettaskcon(pid_t target, char **con, char **mode)
 
522
{
 
523
        return aa_getprocattr(target, "current", con, mode);
 
524
}
 
525
 
 
526
/**
 
527
 * aa_getcon - get the confinement for current task in an allocated buffer
 
528
 * @con: pointer to return buffer with the confinement if successful
 
529
 * @mode: if provided will point to the mode string in @con if present
 
530
 *
 
531
 * Returns: length of confinement data or -1 on error and sets errno
 
532
 *
 
533
 * Guarentees that @con and @mode are null terminated.  The length returned
 
534
 * is for all data including both @con and @mode, and may > than strlen(@con)
 
535
 * even if @mode is NULL
 
536
 *
 
537
 * Caller is responsible for freeing the buffer returned in @con.  @mode is
 
538
 * always contained within @con's buffer and so NEVER do free(@mode)
 
539
 */
 
540
int aa_getcon(char **con, char **mode)
 
541
{
 
542
        return aa_gettaskcon(aa_gettid(), con, mode);
 
543
}
 
544
 
 
545
 
 
546
#ifndef SO_PEERSEC
 
547
#define SO_PEERSEC 31
 
548
#endif
 
549
 
 
550
/**
 
551
 * aa_getpeercon_raw - get the confinement of the socket's peer (other end)
 
552
 * @fd: socket to get peer confinement for
 
553
 * @con: pointer to buffer to store confinement string
 
554
 * @size: initially contains size of the buffer, returns size of data read
 
555
 *
 
556
 * Returns: length of confinement data including null termination or -1 on error
 
557
 *          if errno == ERANGE then @size will hold the size needed
 
558
 */
 
559
int aa_getpeercon_raw(int fd, char *buffer, int *size)
 
560
{
 
561
        socklen_t optlen = *size;
 
562
        int rc;
 
563
 
 
564
        if (optlen <= 0 || buffer == NULL) {
 
565
                errno = EINVAL;
 
566
                return -1;
 
567
        }
 
568
 
 
569
        rc = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, buffer, &optlen);
 
570
        if (rc == -1 || optlen <= 0)
 
571
                goto out;
 
572
 
 
573
        /* check for null termination */
 
574
        if (buffer[optlen - 1] != 0) {
 
575
                if (optlen < *size) {
 
576
                        buffer[optlen] = 0;
 
577
                        optlen++;
 
578
                } else {
 
579
                        /* buffer needs to be bigger by 1 */
 
580
                        rc = -1;
 
581
                        errno = ERANGE;
 
582
                        optlen++;
 
583
                }
 
584
        }
 
585
out:
 
586
        *size = optlen;
 
587
        return rc;
 
588
}
 
589
 
 
590
/**
 
591
 * aa_getpeercon - get the confinement of the socket's peer (other end)
 
592
 * @fd: socket to get peer confinement for
 
593
 * @con: pointer to allocated buffer with the confinement string
 
594
 *
 
595
 * Returns: length of confinement data including null termination or -1 on error
 
596
 *
 
597
 * Caller is responsible for freeing the buffer returned.
 
598
 */
 
599
int aa_getpeercon(int fd, char **con)
 
600
{
 
601
        int rc, size = INITIAL_GUESS_SIZE;
 
602
        char *buffer = NULL;
 
603
 
 
604
        if (!con) {
 
605
                errno = EINVAL;
 
606
                return -1;
 
607
        }
 
608
 
 
609
        do {
 
610
                buffer = realloc(buffer, size);
 
611
                if (!buffer)
 
612
                        return -1;
 
613
                memset(buffer, 0, size);
 
614
 
 
615
                rc = aa_getpeercon_raw(fd, buffer, &size);
 
616
        } while (rc == -1 && errno == ERANGE);
 
617
 
 
618
        if (rc == -1) {
 
619
                free(buffer);
 
620
                size = -1;
 
621
        } else
 
622
                *con = buffer;
 
623
 
 
624
        return size;
 
625
}