~cmiller/ubuntu/trusty/apparmor/chromium-new-sandbox-name

« back to all changes in this revision

Viewing changes to .pc/0053-libapparmor-Export-a-label-based-query-interface.patch/libraries/libapparmor/src/kernel_interface.c

  • Committer: Package Import Robot
  • Author(s): Tyler Hicks, Tyler Hicks, Jamie Strandboge
  • Date: 2013-08-26 15:32:12 UTC
  • Revision ID: package-import@ubuntu.com-20130826153212-va8c7fugv96f6sml
Tags: 2.8.0-0ubuntu25
[ Tyler Hicks ]
* Add support for mediation of D-Bus messages and services. AppArmor D-Bus
  rules are described in the apparmor.d(5) man page. dbus-daemon will use
  libapparmor to perform queries against the AppArmor policies to determine
  if a connection should be able to send messages to another connection, if
  a connection should be able to receive messages from another connection,
  and if a connection should be able to bind to a well-known name.
  - 0042-Fix-mount-rule-preprocessor-output.patch,
    0043-libapparmor-Safeguard-aa_getpeercon-buffer-reallocat.patch,
    0044-libapparmor-fix-return-value-of-aa_getpeercon_raw.patch,
    0045-libapparmor-Move-mode-parsing-into-separate-function.patch,
    0046-libapparmor-Parse-mode-from-confinement-string-in-ge.patch,
    0047-libapparmor-Make-aa_getpeercon_raw-similar-to-aa_get.patch,
    0048-libapparmor-Update-aa_getcon-man-page-to-reflect-get.patch:
    Backport parser and libapparmor pre-requisites for D-Bus mediation
  - 0049-parser-Update-man-page-for-DBus-rules.patch: Update apparmor.d man
    page
  - 0050-parser-Add-support-for-DBus-rules.patch,
    0051-parser-Regression-tests-for-DBus-rules.patch,
    0052-parser-Binary-profile-equality-tests-for-DBus-rules.patch: Add
    apparmor_parser support for D-Bus mediation rules
  - 0053-libapparmor-Export-a-label-based-query-interface.patch,
    debian/libapparmor1.symbols: Provide the libapparmor interface necessary
    for trusted helpers to make security decisions based upon AppArmor
    policy
  - 0054-libaalogparse-Parse-dbus-daemon-audit-messages.patch,
    0055-libaalogparse-Regression-tests-for-dbus-daemon-audit.patch: Allow
    applications to parse denials, generated by dbus-daemon, using
    libaalogparse and add a set of regression tests
  - 0056-tests-Add-an-optional-final-check-to-checktestfg.patch,
    0057-tests-Add-required-features-check.patch,
    0058-tests-Add-regression-tests-for-dbus.patch: Add regression tests
    which start their own dbus-daemon, load profiles containing D-Bus rules,
    and confine simple D-Bus service and client applications
  - 0059-dbus-rules-for-dbus-abstractions.patch: Add bus-specific, but
    otherwise permissive, D-Bus rules to the dbus and dbus-session
    abstractions. Confined applications that use D-Bus should already be
    including these abstractions in their profiles so this should be a
    seamless transition for those profiles.
* 0060-utils-make_clean_fixup.patch: Clean up the Python cache in the
  AppArmor tests directory
* 0061-profiles-dnsmasq-needs-dbus-abstraction.patch: Dnsmasq uses the
  system D-Bus when it is started with --enable-dbus, so its AppArmor
  profile needs to include the system bus abstraction
* 0062-fix-clone-test-on-arm.patch: Fix compiler error when building
  regression tests on ARM
* 0063-utils-ignore-unsupported-rules.patch: Utilities that use the
  Immunix::AppArmor perl module, such as aa-logprof and aa-genprof, error
  out when they encounter rules unsupported by the perl module. This patch
  ignores unsupported rules.

[ Jamie Strandboge ]
* debian/control: don't have easyprof Depends on apparmor-easyprof-ubuntu

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 2003-2008 Novell, Inc. (All rights reserved)
 
3
 * Copyright 2009-2010 Canonical Ltd.
 
4
 *
 
5
 * The libapparmor library is licensed under the terms of the GNU
 
6
 * Lesser General Public License, version 2.1. Please see the file
 
7
 * COPYING.LGPL.
 
8
 *
 
9
 * This library is distributed in the hope that it will be useful,
 
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
 * GNU Lesser General Public License for more details.
 
13
 *
 
14
 * You should have received a copy of the GNU Lesser General Public License
 
15
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
16
 */
 
17
 
 
18
#include <stdlib.h>
 
19
#include <stdio.h>
 
20
#include <string.h>
 
21
#include <unistd.h>
 
22
#include <sys/types.h>
 
23
#include <sys/stat.h>
 
24
#include <sys/syscall.h>
 
25
#include <sys/socket.h>
 
26
#include <fcntl.h>
 
27
#include <errno.h>
 
28
#include <limits.h>
 
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
 
38
 
 
39
#define symbol_version(real, name, version) \
 
40
                __asm__ (".symver " #real "," #name "@" #version)
 
41
#define default_symbol_version(real, name, version) \
 
42
                __asm__ (".symver " #real "," #name "@@" #version)
 
43
 
 
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
 * parse_confinement_mode - get the mode from the confinement string
 
154
 * @con: the confinement string
 
155
 * @size: size of the confinement string
 
156
 *
 
157
 * Modifies con to NUL-terminate the label string and the mode string.
 
158
 *
 
159
 * Returns: a pointer to the NUL-terminated mode inside the confinement string
 
160
 * or NULL if the mode was not found
 
161
 */
 
162
static char *parse_confinement_mode(char *con, int size)
 
163
{
 
164
        if (strcmp(con, "unconfined") != 0 &&
 
165
            size > 4 && con[size - 2] == ')') {
 
166
                int pos = size - 3;
 
167
 
 
168
                while (pos > 0 && !(con[pos] == ' ' && con[pos + 1] == '('))
 
169
                        pos--;
 
170
                if (pos > 0) {
 
171
                        con[pos] = 0; /* overwrite ' ' */
 
172
                        con[size - 2] = 0; /* overwrite trailing ) */
 
173
                        return &con[pos + 2]; /* skip '(' */
 
174
                }
 
175
        }
 
176
        return NULL;
 
177
}
 
178
 
 
179
/**
 
180
 * aa_getprocattr_raw - get the contents of @attr for @tid into @buf
 
181
 * @tid: tid of task to query
 
182
 * @attr: which /proc/<tid>/attr/<attr> to query
 
183
 * @buf: buffer to store the result in
 
184
 * @len: size of the buffer
 
185
 * @mode: if set will point to mode string within buffer if it is present
 
186
 *
 
187
 * Returns: size of data read or -1 on error, and sets errno
 
188
 */
 
189
int aa_getprocattr_raw(pid_t tid, const char *attr, char *buf, int len,
 
190
                       char **mode)
 
191
{
 
192
        int rc = -1;
 
193
        int fd, ret;
 
194
        char *tmp = NULL;
 
195
        int size = 0;
 
196
 
 
197
        if (!buf || len <= 0) {
 
198
                errno = EINVAL;
 
199
                goto out;
 
200
        }
 
201
 
 
202
        tmp = procattr_path(tid, attr);
 
203
        if (!tmp)
 
204
                goto out;
 
205
 
 
206
        fd = open(tmp, O_RDONLY);
 
207
        free(tmp);
 
208
        if (fd == -1) {
 
209
                goto out;
 
210
        }
 
211
 
 
212
        tmp = buf;
 
213
        do {
 
214
                ret = read(fd, tmp, len);
 
215
                if (ret <= 0)
 
216
                        break;
 
217
                tmp += ret;
 
218
                size += ret;
 
219
                len -= ret;
 
220
                if (len < 0) {
 
221
                        errno = ERANGE;
 
222
                        goto out2;
 
223
                }
 
224
        } while (ret > 0);
 
225
 
 
226
        if (ret < 0) {
 
227
                int saved;
 
228
                if (ret != -1) {
 
229
                        errno = EPROTO;
 
230
                }
 
231
                saved = errno;
 
232
                (void)close(fd);
 
233
                errno = saved;
 
234
                goto out;
 
235
        } else if (size > 0 && buf[size - 1] != 0) {
 
236
                /* check for null termination */
 
237
                if (buf[size - 1] == '\n') {
 
238
                        buf[size - 1] = 0;
 
239
                } else if (len == 0) {
 
240
                        errno = ERANGE;
 
241
                        goto out2;
 
242
                } else {
 
243
                        buf[size] = 0;
 
244
                        size++;
 
245
                }
 
246
 
 
247
                if (mode)
 
248
                        *mode = parse_confinement_mode(buf, size);
 
249
        }
 
250
        rc = size;
 
251
 
 
252
out2:
 
253
        (void)close(fd);
 
254
out:
 
255
        return rc;
 
256
}
 
257
 
 
258
#define INITIAL_GUESS_SIZE 128
 
259
 
 
260
/**
 
261
 * aa_getprocattr - get the contents of @attr for @tid into @buf
 
262
 * @tid: tid of task to query
 
263
 * @attr: which /proc/<tid>/attr/<attr> to query
 
264
 * @buf: allocated buffer the result is stored in
 
265
 * @mode: if set will point to mode string within buffer if it is present
 
266
 *
 
267
 * Returns: size of data read or -1 on error, and sets errno
 
268
 */
 
269
int aa_getprocattr(pid_t tid, const char *attr, char **buf, char **mode)
 
270
{
 
271
        int rc, size = INITIAL_GUESS_SIZE/2;
 
272
        char *buffer = NULL;
 
273
 
 
274
        if (!buf) {
 
275
                errno = EINVAL;
 
276
                return -1;
 
277
        }
 
278
 
 
279
        do {
 
280
                size <<= 1;
 
281
                buffer = realloc(buffer, size);
 
282
                if (!buffer)
 
283
                        return -1;
 
284
                memset(buffer, 0, size);
 
285
 
 
286
                rc = aa_getprocattr_raw(tid, attr, buffer, size, mode);
 
287
        } while (rc == -1 && errno == ERANGE);
 
288
 
 
289
        if (rc == -1) {
 
290
                free(buffer);
 
291
                *buf = NULL;
 
292
                *mode = NULL;
 
293
        } else
 
294
                *buf = buffer;
 
295
 
 
296
        return rc;
 
297
}
 
298
 
 
299
static int setprocattr(pid_t tid, const char *attr, const char *buf, int len)
 
300
{
 
301
        int rc = -1;
 
302
        int fd, ret;
 
303
        char *ctl = NULL;
 
304
 
 
305
        if (!buf) {
 
306
                errno = EINVAL;
 
307
                goto out;
 
308
        }
 
309
 
 
310
        ctl = procattr_path(tid, attr);
 
311
        if (!ctl)
 
312
                goto out;
 
313
 
 
314
        fd = open(ctl, O_WRONLY);
 
315
        if (fd == -1) {
 
316
                goto out;
 
317
        }
 
318
 
 
319
        ret = write(fd, buf, len);
 
320
        if (ret != len) {
 
321
                int saved;
 
322
                if (ret != -1) {
 
323
                        errno = EPROTO;
 
324
                }
 
325
                saved = errno;
 
326
                (void)close(fd);
 
327
                errno = saved;
 
328
                goto out;
 
329
        }
 
330
 
 
331
        rc = 0;
 
332
        (void)close(fd);
 
333
 
 
334
out:
 
335
        if (ctl) {
 
336
                free(ctl);
 
337
        }
 
338
        return rc;
 
339
}
 
340
 
 
341
int aa_change_hat(const char *subprofile, unsigned long token)
 
342
{
 
343
        int rc = -1;
 
344
        int len = 0;
 
345
        char *buf = NULL;
 
346
        const char *fmt = "changehat %016x^%s";
 
347
 
 
348
        /* both may not be null */
 
349
        if (!(token || subprofile)) {
 
350
                errno = EINVAL;
 
351
                goto out;
 
352
        }
 
353
 
 
354
        if (subprofile && strnlen(subprofile, PATH_MAX + 1) > PATH_MAX) {
 
355
                errno = EPROTO;
 
356
                goto out;
 
357
        }
 
358
 
 
359
        len = asprintf(&buf, fmt, token, subprofile ? subprofile : "");
 
360
        if (len < 0) {
 
361
                goto out;
 
362
        }
 
363
 
 
364
        rc = setprocattr(aa_gettid(), "current", buf, len);
 
365
out:
 
366
        if (buf) {
 
367
                /* clear local copy of magic token before freeing */
 
368
                memset(buf, '\0', len);
 
369
                free(buf);
 
370
        }
 
371
        return rc;
 
372
}
 
373
 
 
374
/* original change_hat interface */
 
375
int __change_hat(char *subprofile, unsigned int token)
 
376
{
 
377
        return aa_change_hat(subprofile, (unsigned long) token);
 
378
}
 
379
 
 
380
int aa_change_profile(const char *profile)
 
381
{
 
382
        char *buf = NULL;
 
383
        int len;
 
384
        int rc;
 
385
 
 
386
        if (!profile) {
 
387
                errno = EINVAL;
 
388
                return -1;
 
389
        }
 
390
 
 
391
        len = asprintf(&buf, "changeprofile %s", profile);
 
392
        if (len < 0)
 
393
                return -1;
 
394
 
 
395
        rc = setprocattr(aa_gettid(), "current", buf, len);
 
396
 
 
397
        free(buf);
 
398
        return rc;
 
399
}
 
400
 
 
401
int aa_change_onexec(const char *profile)
 
402
{
 
403
        char *buf = NULL;
 
404
        int len;
 
405
        int rc;
 
406
 
 
407
        if (!profile) {
 
408
                errno = EINVAL;
 
409
                return -1;
 
410
        }
 
411
 
 
412
        len = asprintf(&buf, "exec %s", profile);
 
413
        if (len < 0)
 
414
                return -1;
 
415
 
 
416
        rc = setprocattr(aa_gettid(), "exec", buf, len);
 
417
 
 
418
        free(buf);
 
419
        return rc;
 
420
}
 
421
 
 
422
/* create an alias for the old change_hat@IMMUNIX_1.0 symbol */
 
423
extern typeof((__change_hat)) __old_change_hat __attribute__((alias ("__change_hat")));
 
424
symbol_version(__old_change_hat, change_hat, IMMUNIX_1.0);
 
425
default_symbol_version(__change_hat, change_hat, APPARMOR_1.0);
 
426
 
 
427
 
 
428
int aa_change_hatv(const char *subprofiles[], unsigned long token)
 
429
{
 
430
        int size, totallen = 0, hatcount = 0;
 
431
        int rc = -1;
 
432
        const char **hats;
 
433
        char *pos, *buf = NULL;
 
434
        const char *cmd = "changehat";
 
435
 
 
436
        /* both may not be null */
 
437
        if (!token && !(subprofiles && *subprofiles)) {
 
438
                errno = EINVAL;
 
439
                goto out;
 
440
        }
 
441
 
 
442
        /* validate hat lengths and while we are at it count how many and
 
443
         * mem required */
 
444
        if (subprofiles) {
 
445
                for (hats = subprofiles; *hats; hats++) {
 
446
                        int len = strnlen(*hats, PATH_MAX + 1);
 
447
                        if (len > PATH_MAX) {
 
448
                                errno = EPROTO;
 
449
                                goto out;
 
450
                        }
 
451
                        totallen += len + 1;
 
452
                        hatcount++;
 
453
                }
 
454
        }
 
455
 
 
456
        /* allocate size of cmd + space + token + ^ + vector of hats */
 
457
        size = strlen(cmd) + 18 + totallen + 1;
 
458
        buf = malloc(size);
 
459
        if (!buf) {
 
460
                goto out;
 
461
        }
 
462
 
 
463
        /* setup command string which is of the form
 
464
         * changehat <token>^hat1\0hat2\0hat3\0..\0
 
465
         */
 
466
        sprintf(buf, "%s %016lx^", cmd, token);
 
467
        pos = buf + strlen(buf);
 
468
        if (subprofiles) {
 
469
                for (hats = subprofiles; *hats; hats++) {
 
470
                        strcpy(pos, *hats);
 
471
                        pos += strlen(*hats) + 1;
 
472
                }
 
473
        } else
 
474
                /* step pos past trailing \0 */
 
475
                pos++;
 
476
 
 
477
        rc = setprocattr(aa_gettid(), "current", buf, pos - buf);
 
478
 
 
479
out:
 
480
        if (buf) {
 
481
                /* clear local copy of magic token before freeing */
 
482
                memset(buf, '\0', size);
 
483
                free(buf);
 
484
        }
 
485
 
 
486
        return rc;
 
487
}
 
488
 
 
489
/**
 
490
 * change_hat_vargs - change_hatv but passing the hats as fn arguments
 
491
 * @token: the magic token
 
492
 * @nhat: the number of hats being passed in the arguments
 
493
 * ...: a argument list of const char * being passed
 
494
 *
 
495
 * change_hat_vargs can be called directly but it is meant to be called
 
496
 * through its macro wrapper of the same name.  Which automatically
 
497
 * fills in the nhats arguments based on the number of parameters
 
498
 * passed.
 
499
 * to call change_hat_vargs direction do
 
500
 * (change_hat_vargs)(token, nhats, hat1, hat2...)
 
501
 */
 
502
int (aa_change_hat_vargs)(unsigned long token, int nhats, ...)
 
503
{
 
504
        va_list ap;
 
505
        const char *argv[nhats+1];
 
506
        int i;
 
507
 
 
508
        va_start(ap, nhats);
 
509
        for (i = 0; i < nhats ; i++) {
 
510
                argv[i] = va_arg(ap, char *);
 
511
        }
 
512
        argv[nhats] = NULL;
 
513
        va_end(ap);
 
514
        return aa_change_hatv(argv, token);
 
515
}
 
516
 
 
517
/**
 
518
 * aa_gettaskcon - get the confinement for task @target in an allocated buffer
 
519
 * @target: task to query
 
520
 * @con: pointer to returned buffer with the confinement string
 
521
 * @mode: if provided will point to the mode string in @con if present
 
522
 *
 
523
 * Returns: length of confinement data or -1 on error and sets errno
 
524
 *
 
525
 * Guarentees that @con and @mode are null terminated.  The length returned
 
526
 * is for all data including both @con and @mode, and maybe > than strlen(@con)
 
527
 * even if @mode is NULL
 
528
 *
 
529
 * Caller is responsible for freeing the buffer returned in @con.  @mode is
 
530
 * always contained within @con's buffer and so NEVER do free(@mode)
 
531
 */
 
532
int aa_gettaskcon(pid_t target, char **con, char **mode)
 
533
{
 
534
        return aa_getprocattr(target, "current", con, mode);
 
535
}
 
536
 
 
537
/**
 
538
 * aa_getcon - get the confinement for current task in an allocated buffer
 
539
 * @con: pointer to return buffer with the confinement if successful
 
540
 * @mode: if provided will point to the mode string in @con if present
 
541
 *
 
542
 * Returns: length of confinement data or -1 on error and sets errno
 
543
 *
 
544
 * Guarentees that @con and @mode are null terminated.  The length returned
 
545
 * is for all data including both @con and @mode, and may > than strlen(@con)
 
546
 * even if @mode is NULL
 
547
 *
 
548
 * Caller is responsible for freeing the buffer returned in @con.  @mode is
 
549
 * always contained within @con's buffer and so NEVER do free(@mode)
 
550
 */
 
551
int aa_getcon(char **con, char **mode)
 
552
{
 
553
        return aa_gettaskcon(aa_gettid(), con, mode);
 
554
}
 
555
 
 
556
 
 
557
#ifndef SO_PEERSEC
 
558
#define SO_PEERSEC 31
 
559
#endif
 
560
 
 
561
/**
 
562
 * aa_getpeercon_raw - get the confinement of the socket's peer (other end)
 
563
 * @fd: socket to get peer confinement for
 
564
 * @buf: buffer to store the result in
 
565
 * @len: initially contains size of the buffer, returns size of data read
 
566
 * @mode: if set will point to mode string within buffer if it is present
 
567
 *
 
568
 * Returns: length of confinement data including null termination or -1 on error
 
569
 *          if errno == ERANGE then @len will hold the size needed
 
570
 */
 
571
int aa_getpeercon_raw(int fd, char *buf, int *len, char **mode)
 
572
{
 
573
        socklen_t optlen = *len;
 
574
        char *mode_str;
 
575
        int rc;
 
576
 
 
577
        if (optlen <= 0 || buf == NULL) {
 
578
                errno = EINVAL;
 
579
                return -1;
 
580
        }
 
581
 
 
582
        rc = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, buf, &optlen);
 
583
        if (rc == -1 || optlen <= 0)
 
584
                goto out;
 
585
 
 
586
        /* check for null termination */
 
587
        if (buf[optlen - 1] != 0) {
 
588
                if (optlen < *len) {
 
589
                        buf[optlen] = 0;
 
590
                        optlen++;
 
591
                } else {
 
592
                        /* buf needs to be bigger by 1 */
 
593
                        rc = -1;
 
594
                        errno = ERANGE;
 
595
                        optlen++;
 
596
                        goto out;
 
597
                }
 
598
        }
 
599
 
 
600
        mode_str = parse_confinement_mode(buf, optlen);
 
601
        if (mode)
 
602
                *mode = mode_str;
 
603
 
 
604
        rc = optlen;
 
605
out:
 
606
        *len = optlen;
 
607
        return rc;
 
608
}
 
609
 
 
610
/**
 
611
 * aa_getpeercon - get the confinement of the socket's peer (other end)
 
612
 * @fd: socket to get peer confinement for
 
613
 * @con: pointer to allocated buffer with the confinement string
 
614
 * @mode: if provided will point to the mode string in @con if present
 
615
 *
 
616
 * Returns: length of confinement data including null termination or -1 on error
 
617
 *
 
618
 * Caller is responsible for freeing the buffer returned.
 
619
 */
 
620
int aa_getpeercon(int fd, char **con, char **mode)
 
621
{
 
622
        int rc, last_size, size = INITIAL_GUESS_SIZE;
 
623
        char *buffer = NULL;
 
624
 
 
625
        if (!con) {
 
626
                errno = EINVAL;
 
627
                return -1;
 
628
        }
 
629
 
 
630
        do {
 
631
                last_size = size;
 
632
                buffer = realloc(buffer, size);
 
633
                if (!buffer)
 
634
                        return -1;
 
635
                memset(buffer, 0, size);
 
636
 
 
637
                rc = aa_getpeercon_raw(fd, buffer, &size, mode);
 
638
                /* size should contain actual size needed if errno == ERANGE */
 
639
        } while (rc == -1 && errno == ERANGE && size > last_size);
 
640
 
 
641
        if (rc == -1) {
 
642
                free(buffer);
 
643
                *con = NULL;
 
644
                if (mode)
 
645
                        *mode = NULL;
 
646
                size = -1;
 
647
        } else
 
648
                *con = buffer;
 
649
 
 
650
        return size;
 
651
}