File: ima.c

package info (click to toggle)
rpm 6.0.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 6,580 kB
  • sloc: cpp: 53,319; ansic: 13,888; sh: 2,038; python: 1,175; makefile: 35; xml: 26
file content (102 lines) | stat: -rw-r--r-- 2,737 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
#include "system.h"

#include <errno.h>
#include <sys/xattr.h>

#include <rpm/rpmfi.h>
#include <rpm/rpmte.h>
#include <rpm/rpmfiles.h>
#include <rpm/rpmtypes.h>
#include <rpm/rpmlog.h>
#include <rpm/rpmstring.h>
#include <rpm/rpmmacro.h>
#include <rpm/rpmplugin.h>

#define XATTR_NAME_IMA "security.ima"

static int write_signatures_on_config_files = 0;

/*
 * check_zero_hdr: Check the signature for a zero header
 *
 * Check whether the given signature has a header with all zeros
 *
 * Returns -1 in case the signature is too short to compare
 * (invalid signature), 0 in case the header is not only zeroes,
 * and 1 if it is only zeroes.
 */
static int check_zero_hdr(const unsigned char *fsig, size_t siglen)
{
	/*
	 * Every signature has a header signature_v2_hdr as defined in
	 * Linux's (4.5) security/integrity/integtrity.h. The following
	 * 9 bytes represent this header in front of the signature.
	 */
	static const uint8_t zero_hdr[] = {0, 0, 0, 0, 0, 0, 0, 0, 0};

	if (siglen < sizeof(zero_hdr))
		return -1;
	return (memcmp(fsig, &zero_hdr, sizeof(zero_hdr)) == 0);
}

static rpmRC ima_fsm_file_prepare(rpmPlugin plugin, rpmfi fi, int fd,
                                  const char *path,
                                  const char *dest,
                                  mode_t file_mode, rpmFsmOp op)
{
	const unsigned char * fsig = NULL;
	size_t len;
	rpmRC rc = RPMRC_OK;
	rpmFileAction action = XFO_ACTION(op);

	/* Ignore skipped files and unowned directories */
	if (XFA_SKIPPING(action) || (op & FAF_UNOWNED))
	    goto exit;

	/* Don't install signatures for (mutable) files marked
	 * as config files unless they are also executable or
	 * user specifically asks for it.
	 */
	if (rpmfiFFlags(fi) & RPMFILE_CONFIG) {
	    if (!(rpmfiFMode(fi) & (S_IXUSR|S_IXGRP|S_IXOTH)) &&
	        !write_signatures_on_config_files)
		goto exit;
	}

	fsig = rpmfiFSignature(fi, &len);
	if (fsig && (check_zero_hdr(fsig, len) == 0)) {
	    int xx;
	    if (fd >= 0)
		xx = fsetxattr(fd, XATTR_NAME_IMA, fsig, len, 0);
	    else
		xx = lsetxattr(path, XATTR_NAME_IMA, fsig, len, 0);
	    if (xx < 0) {
		/* unsupported fs or root inside rootless container? */
		int is_err = !(errno == EOPNOTSUPP ||
			      (errno == EPERM && getuid() == 0));

	        rpmlog(is_err?RPMLOG_ERR:RPMLOG_DEBUG,
			"ima: could not apply signature on '%s': %s\n",
			path, strerror(errno));
		if (is_err) {
		    rc = RPMRC_FAIL;
		}
	    }
	}

exit:
	return rc;
}

static rpmRC ima_init(rpmPlugin plugin, rpmts ts)
{
	write_signatures_on_config_files =
	    rpmExpandNumeric("%{?_ima_sign_config_files}");

	return RPMRC_OK;
}

struct rpmPluginHooks_s ima_hooks = {
        .init = ima_init,
	.fsm_file_prepare = ima_fsm_file_prepare,
};