aboutsummaryrefslogtreecommitdiff
blob: d499d9bd04a4277666872eab8cfb25749a1f6061 (plain)
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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# (c) 2017, Alice Ferrazzi <alice.ferrazzi@gmail.com>
# Distributed under the terms of the GNU General Public License v2 or later

import subprocess
import os
import fileinput
import tempfile


class PaTch(object):

    def __init__(self):
        pass

    def build_livepatch(self, uuid, vmlinux, debug=True):
        """
        Function for building the livepatch

        :param uuid: UUID session identification
        :param vmlinux: path to the vmlinux file
        :param debug: copy build.log in the uuid directory
        :return: void
        """
        kernel_source = os.path.join('/tmp/', 'elivepatch-' + uuid, 'usr/src/linux/')
        uuid_dir = os.path.join('/tmp/', 'elivepatch-' + uuid)
        vmlinux_source = os.path.join(kernel_source, vmlinux)
        kpatch_cachedir = os.path.join(uuid_dir, 'kpatch')

        os.makedirs(kpatch_cachedir)
        if not os.path.isfile(vmlinux_source):
            self.build_kernel(uuid)

        bashCommand = ['kpatch-build']
        bashCommand.extend(['-s', kernel_source])
        bashCommand.extend(['-v', vmlinux_source])
        bashCommand.extend(['-c', 'config'])
        bashCommand.extend(['main.patch'])
        bashCommand.extend(['--skip-gcc-check'])
        if debug:
            bashCommand.extend(['--skip-cleanup'])
            bashCommand.extend(['--debug'])
        _command(bashCommand, uuid_dir, {'CACHEDIR': kpatch_cachedir})
        if debug:
            _command(['cp', '-f', os.path.join(kpatch_cachedir, 'build.log'), uuid_dir])

    def get_kernel_sources(self, uuid, kernel_version, debug=True):
        """
        Function for download the kernel sources

        :return: void
        """
        try:
            _command(['git', 'clone', 'https://github.com/aliceinwire/gentoo-sources_overlay.git'])
        except:
            print('git clone failed.')

        uuid_dir = os.path.join('/tmp/', 'elivepatch-' + uuid)
        ebuild_path = os.path.join('gentoo-sources_overlay', 'sys-kernel', 'gentoo-sources', 'gentoo-sources-' +
                                   kernel_version + '.ebuild')
        print(ebuild_path)
        if os.path.isfile(ebuild_path):
            # Use a private tmpdir for portage
            with tempfile.TemporaryDirectory(dir=uuid_dir) as portage_tmpdir:
                print('uuid_dir: ' + str(uuid_dir) + ' PORTAGE_TMPDIR: ' + str(portage_tmpdir))
                # portage_tmpdir is not always working with root privileges
                if debug:
                    if os.geteuid() != 0:
                        env = {'ROOT': uuid_dir, 'PORTAGE_CONFIGROOT': uuid_dir, 'PORTAGE_TMPDIR': portage_tmpdir,
                               'PORTAGE_DEBUG': '1'}
                    else:
                        env = {'ROOT': uuid_dir, 'PORTAGE_CONFIGROOT': uuid_dir, 'PORTAGE_TMPDIR': uuid_dir,
                               'PORTAGE_DEBUG': '1'}
                else:
                    if os.geteuid() != 0:
                        env = {'ROOT': uuid_dir, 'PORTAGE_CONFIGROOT': uuid_dir, 'PORTAGE_TMPDIR': portage_tmpdir}
                    else:
                        env = {'ROOT': uuid_dir, 'PORTAGE_CONFIGROOT': uuid_dir, 'PORTAGE_TMPDIR': uuid_dir}
                _command(['ebuild', ebuild_path, 'digest', 'clean', 'merge'], env=env)
                kernel_sources_status = True
        else:
            print('ebuild not present')
            kernel_sources_status = None
        return kernel_sources_status

    def build_kernel(self, uuid):
        kernel_source_dir = '/tmp/elivepatch-' + uuid + '/usr/src/linux/'
        uuid_dir_config = '/tmp/elivepatch-' + uuid + '/config'
        if 'CONFIG_DEBUG_INFO=y' in open(uuid_dir_config).read():
            print("DEBUG_INFO correctly present")
        elif 'CONFIG_DEBUG_INFO=n' in open(uuid_dir_config).read():
            print("changing DEBUG_INFO to yes")
            for line in fileinput.input(uuid_dir_config, inplace=1):
                print(line.replace("CONFIG_DEBUG_INFO=n", "CONFIG_DEBUG_INFO=y"))
        else:
            print("Adding DEBUG_INFO for getting kernel debug symbols")
            for line in fileinput.input(uuid_dir_config, inplace=1):
                print(line.replace("# CONFIG_DEBUG_INFO is not set", "CONFIG_DEBUG_INFO=y"))
        _command(['cp', '/tmp/elivepatch-' + uuid + '/config', kernel_source_dir + '.config'])
        # olddefconfig default everything that is new from the configuration file
        _command(['make', 'olddefconfig'], kernel_source_dir)
        _command(['make'], kernel_source_dir)
        _command(['make', 'modules'], kernel_source_dir)


def _command(bashCommand, kernel_source_dir=None, env=None):
        """
        Popen override function

        :param bashCommand: List of command arguments to execute
        :param kernel_source_dir: String with the directory where the command is executed
        :param env: Dictionary for setting system environment variable
        :return: void
        """
        # Inherit the parent environment and update the private copy
        if env:
            process_env = os.environ.copy()
            process_env.update(env)
            env = process_env

        if kernel_source_dir:
            print(bashCommand)
            process = subprocess.Popen(bashCommand, stdout=subprocess.PIPE,  cwd=kernel_source_dir, env=env)
            output, error = process.communicate()
            for output_line in output.split(b'\n'):
                print(output_line.strip())
        else:
            print(bashCommand)
            process = subprocess.Popen(bashCommand, stdout=subprocess.PIPE, env=env)
            output, error = process.communicate()
            for output_line in output.split(b'\n'):
                print(output_line.strip())