Check-in [fb468fff0e]

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Integrated SetUID support
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: fb468fff0e28e580499feb01831531b4eec9016b
User & Date: rkeene 2020-08-23 19:48:47
Context
2020-08-23
21:30
Improved ignores check-in: 2a95820227 user: rkeene tags: trunk
19:48
Integrated SetUID support check-in: fb468fff0e user: rkeene tags: trunk
19:48
Do not redirect from HTTPS to HTTP when not needed check-in: cfe1899bbb user: rkeene tags: trunk
19:41
Update automated rebuild to use suid fossil Closed-Leaf check-in: 302ba97f86 user: rkeene tags: setuid-fossil
Changes

Added .fossil-settings/ignore-glob.







>
>
>
1
2
3
scripts/fossil-as-user/secure-wrap
scripts/fossil-as-user/filter.h
repos/*

Changes to nano/db.php.

32
33
34
35
36
37
38

39
40
41
42
43
44
45
..
47
48
49
50
51
52
53

54
55
56
57
58
59
60
61
62
63
64
65
66

    public static function execute($sql, $bind = array())
    {
        $res = self::$_db->prepare($sql);

	if ($res === false) {
            error_log("Unable to prepare (for execution): {$sql}: " . implode(self::$_db->errorInfo()));

	}

        if ($res->execute($bind)) {
            return true;
        }

        return false;
................................................................................

    public static function query($sql, $bind = array())
    {
        $res = self::$_db->prepare($sql);

	if ($res === false) {
            error_log("Unable to prepare (for query): {$sql}: " . implode(self::$_db->errorInfo()));

	}

        if ($res->execute($bind)) {
            if ($result = $res->fetchAll(PDO::FETCH_ASSOC)) {
                return $result;
            }
        }

        return false;
    }
}

Nano_Db::init();







>







 







>













32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
..
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68

    public static function execute($sql, $bind = array())
    {
        $res = self::$_db->prepare($sql);

	if ($res === false) {
            error_log("Unable to prepare (for execution): {$sql}: " . implode(self::$_db->errorInfo()));
            return false;
	}

        if ($res->execute($bind)) {
            return true;
        }

        return false;
................................................................................

    public static function query($sql, $bind = array())
    {
        $res = self::$_db->prepare($sql);

	if ($res === false) {
            error_log("Unable to prepare (for query): {$sql}: " . implode(self::$_db->errorInfo()));
            return false;
	}

        if ($res->execute($bind)) {
            if ($result = $res->fetchAll(PDO::FETCH_ASSOC)) {
                return $result;
            }
        }

        return false;
    }
}

Nano_Db::init();

Changes to nano/fossil.php.

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


135
136
137
138

139
140


141
142
143




144
145
146
147
148
149
150
151


152
153
154
155
156
157
158

159
160
161
162

163



164
165
166
167
168
169


170
171
172
173



174

175
176
177
178
179

180
181


182
183

184
185
186
187
188



189
190
191

192
193
194
195



196
197
198
199


200
201
202
203


204
205






206
207

208

209
210
211
212
213


214
215
216
217
218
219



220
221
222
223
224
225
226
227


228
229
230
231

232
233

234
235
236
237
238
239
240
241




242
243
244

245
246
247
248
249
250
251
252
253
254
255
256
257
258


259
260
261
262
263


264
265
266

267
268
269
270
271

272
273
274
275
276
277
278
279
280






281
282
283

284

285
286
287
288
289
290

291
292
293

294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378

379

380


381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398

399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415


416

417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434

435
436
437
438
439



440
441
442
443
444
445
446
447
448
449

450
451


452
453
454
455
456
457



458





459
460
461













<?php

class Nano_Fossil
{


    protected $path;

    protected $user;
    protected $workdir;



    public function __construct($user)
    {
        $this->path = $_SERVER['DOCUMENT_ROOT'] . '/../repos/' . $user['username'] . '/';


        $this->user = $user;





























        $this->workdir = "/tmp/workdir-flint-" . bin2hex(openssl_random_pseudo_bytes(20));

        mkdir($this->workdir);
    }


    public function __destruct() {

        system("rm -rf '{$this->workdir}'");

















    }

    private function getFossilCommand($timeout = 0, $cgi = false) {
        $fossil = "/usr/local/bin/fossil";

        if ($timeout) {
            $fossil = "timeout {$timeout} {$fossil}";
        }

        $username = escapeshellarg($this->user['username']);




        $cmd = "HOME={$this->workdir} USER={$username} {$fossil}";





        if ($cgi) {
            $cmd = "GATEWAY_INTERFACE=1 {$cmd}";
        } else {
            $cmd = "unset GATEWAY_INTERFACE; {$cmd}";
        }

        return $cmd;
    }

    public function newRepo($repo, $password = null, $private = 0, $projectCode = null, $sha3 = false)





    {



















        if (!file_exists($this->path)) {

            mkdir($this->path);

            $content = "#!/usr/local/bin/fossil\ndirectory: ./\nnotfound: http://{$_SERVER['SERVER_NAME']}/notfound";
            file_put_contents("{$this->path}repository", $content);
            chmod("{$this->path}repository", 0555);
        }

        if ($sha3 === true) {
            $shaArg = "";
        } else {
            $shaArg = "--sha1";
        }









        if (!file_exists("{$this->path}{$repo}.fossil")) {
            exec($this->getFossilCommand() . " new " . $shaArg . " -A " . escapeshellarg($this->user['username']) . " " . escapeshellarg("{$this->path}{$repo}.fossil"), $output, $return);


            if ($return !== 0) {
                if (file_exists("{$this->path}{$repo}.fossil")) {
                    unlink("{$this->path}{$repo}.fossil");
                }




                return false;

            }


            /* Install default configuration */
            exec($this->getFossilCommand() . " configuration import -R " . escapeshellarg("{$this->path}{$repo}.fossil") . " " . escapeshellarg($_SERVER['DOCUMENT_ROOT'] . "/../config/fossil-default.cnf"), $output, $return);



            $sql = "INSERT INTO repositories
                           (user_id, name, private, cloned, auto_update)
                    VALUES (:id, :name, :private, 0, 0)";



            $bind = array('id' => $this->user['id'], 'name' => $repo, 'private' => $private);

            if (Nano_Db::execute($sql, $bind)) {
                Nano_Db::setDb("sqlite:{$this->path}{$repo}.fossil");

                if ($projectCode) {
                    $sql  = "UPDATE config SET value = :code WHERE name = 'project-code'";
                    $bind = array('code' => $projectCode);
                    Nano_Db::execute($sql, $bind);

                }


                if ($password) {
                    $sql = "SELECT value FROM config WHERE name = 'project-code'";


                    if ($result = Nano_Db::query($sql)) {
                        $code     = array_pop($result);
                        $password = sha1("{$code['value']}/{$this->user['username']}/{$password}");

                        $sql  = "UPDATE user SET pw = :password WHERE login = :user";
                        $bind = array('password' => $password, 'user' => $this->user['username']);
                        Nano_Db::execute($sql, $bind);



                        $return = 'sha1';
                    }
                }
                else {
                    $sql  = "SELECT pw FROM user WHERE login = :user";
                    $bind = array('user' => $this->user['username']);


                    if ($result = Nano_Db::query($sql, $bind)) {
                        $password = array_pop($result);
                        $return   = $password['pw'];
                    }





                }



                $sql = "UPDATE config SET value = 1 WHERE name = 'localauth'";
                Nano_Db::execute($sql);
                Nano_Db::unsetDb();








                return $return;
            }
        }



        return false;

    }



    public function cloneRepo($repo, $password = null, $url, $private = 0, $update = 0)
    {
        if (!file_exists($this->path)) {
            mkdir($this->path);




            $content = "#!/usr/local/bin/fossil\ndirectory: ./\nnotfound: http://{$_SERVER['SERVER_NAME']}/notfound";
            file_put_contents("{$this->path}repository", $content);
            chmod("{$this->path}repository", 0555);

        }

        if (!file_exists("{$this->path}{$repo}.fossil")) {
            exec($this->getFossilCommand(3600) . " clone -A " . escapeshellarg($this->user['username']) . " " . escapeshellarg($url) . " " . escapeshellarg("{$this->path}{$repo}.fossil"), $output,
                 $return);



            if ($return !== 0) {
                if (file_exists("{$this->path}{$repo}.fossil")) {
                    unlink("{$this->path}{$repo}.fossil");

                }



                return false;
            }





            $sql = "INSERT INTO repositories
                           (user_id, name, private, cloned, auto_update)
                    VALUES (:id, :name, :private, 1, :auto)";

            $bind = array('id' => $this->user['id'], 'name' => $repo, 'private' => $private, 'auto' => $update);

            if (Nano_Db::execute($sql, $bind)) {
                Nano_Db::setDb("sqlite:{$this->path}{$repo}.fossil");



                if ($password) {
                    $sql = "SELECT value FROM config WHERE name = 'project-code'";

                    if ($result = Nano_Db::query($sql)) {
                        $code     = array_pop($result);
                        $password = sha1("{$code['value']}/{$this->user['username']}/{$password}");


                        $sql  = "UPDATE user SET pw = :password WHERE login = :user";
                        $bind = array('password' => $password, 'user' => $this->user['username']);
                        Nano_Db::execute($sql, $bind);





                        $return = 'sha1';
                    }
                }
                else {
                    $sql  = "SELECT pw FROM user WHERE login = :user";
                    $bind = array('user' => $this->user['username']);



                    if ($result = Nano_Db::query($sql, $bind)) {
                        $password = array_pop($result);
                        $return   = $password['pw'];



                    }

                }

                $sql = "UPDATE config SET value = 1 WHERE name = 'localauth'";
                Nano_Db::execute($sql);
                Nano_Db::unsetDb();


                return $return;


            }
        }


        return false;
    }

    public function uploadRepo($repo, $password, $private = 0, array $file)



    {
        if (!file_exists($this->path)) {
            mkdir($this->path);


            $content = "#!/usr/local/bin/fossil\ndirectory: ./\nnotfound: http://{$_SERVER['SERVER_NAME']}/notfound";
            file_put_contents("{$this->path}repository", $content);
            chmod("{$this->path}repository", 0555);



        }

        if (!file_exists("{$this->path}{$repo}.fossil")) {
            if (!@move_uploaded_file($file['tmp_name'], "{$this->path}{$repo}.fossil")) {


                return false;
            }

            exec($this->getFossilCommand() . " config -R " . escapeshellarg("{$this->path}{$repo}.fossil") . " export project /tmp/config",


                 $output, $return);







            if (file_exists('/tmp/config')) {
                unlink('/tmp/config');

            }


            if ($return !== 0) {
                if (file_exists("{$this->path}{$repo}.fossil")) {
                    unlink("{$this->path}{$repo}.fossil");
                }



                return false;
            }

            exec($this->getFossilCommand() . " user new " . escapeshellarg($this->user['username']) . " 'Flint User' {$password} -R " . escapeshellarg("{$this->path}{$repo}.fossil"),
                $output, $return);




            if ($return == 0) {
                exec($this->getFossilCommand() . " user capabilities " . escapeshellarg($this->user['username']) . " s -R " . escapeshellarg("{$this->path}{$repo}.fossil"),
                    $output, $return);

                if ($return !== 0) {
                    unlink("{$this->path}{$repo}.fossil");
                    return false;


                }
            }
            else if ($return == 1) {
                Nano_Db::setDb("sqlite:{$this->path}{$repo}.fossil");

                    
                $sql = "SELECT value FROM config WHERE name = 'project-code'";

                    
                if ($result = Nano_Db::query($sql)) {
                    $code     = array_pop($result);
                    $password = sha1("{$code['value']}/{$this->user['username']}/{$password}");
                        
                    $sql  = "UPDATE user SET cap = 's', pw = :password WHERE login = :user";
                    $bind = array('password' => $password, 'user' => $this->user['username']);
                    Nano_Db::execute($sql, $bind);




                }

                Nano_Db::unsetDb();

            }
            else {
                unlink("{$this->path}{$repo}.fossil");
                return false;
            }

            $sql = "INSERT INTO repositories
                           (user_id, name, private, cloned, auto_update)
                    VALUES (:id, :name, :private, 0, 0)";

            $bind = array('id' => $this->user['id'], 'name' => $repo, 'private' => $private);

            if (Nano_Db::execute($sql, $bind)) {
                Nano_Db::setDb("sqlite:{$this->path}{$repo}.fossil");



                $sql = "UPDATE config SET value = 1 WHERE name = 'localauth'";
                Nano_Db::execute($sql);
                Nano_Db::unsetDb();



                return 'sha1';
            }
        }


        return false;
    }

    public function pullRepo($repo, $url = '', &$outputstr = null)

    {
        if ($url != '') {
            if (file_exists($url) || preg_match('/:\/\//', $url) == 0) {
                $outputstr = "Invalid URL";
                return false;
            }
        }

        if (file_exists("{$this->path}{$repo}.fossil")) {






            # Ensure that no non-default SSH command can be used for a pull
            exec($this->getFossilCommand(3600) . " unset ssh-command -R " . escapeshellarg("{$this->path}{$repo}.fossil") . " 2>&1",
              $output, $return);

            if ($return !== 0) {

                return false;
            }

            if ($url == '') {
                exec($this->getFossilCommand(3600) . " pull -R " . escapeshellarg("{$this->path}{$repo}.fossil") . " 2>&1",
                  $output, $return);

            } else {
                exec($this->getFossilCommand(3600) . " pull " . escapeshellarg($url) . " -R " . escapeshellarg("{$this->path}{$repo}.fossil") . " 2>&1",
                  $output, $return);

            }

            $outputstr = join("\n", $output);

            if ($return !== 0) {
                return false;
            }

            return true;
        }

        $outputstr = "Invalid repository";

        return false;
    }

    public function getRepos()
    {
        $sql = "SELECT *
                  FROM repositories
                 WHERE user_id = :id";

        $bind = array('id' => $this->user['id']);

        if ($result = Nano_Db::query($sql, $bind)) {
            return $result;
        }

        return false;
    }

    public function getRepoById($id)
    {
        $sql = "SELECT *
                  FROM repositories
                 WHERE user_id = :user
                   AND id = :id";

        $bind = array('user' => $this->user['id'], 'id' => $id);

        if ($result = Nano_Db::query($sql, $bind)) {
            $return = array_pop($result);
        }
        else {
            return false;
        }

        $return['repo-file'] = "{$this->path}{$return['name']}.fossil";

        Nano_Db::setDb("sqlite:{$this->path}{$return['name']}.fossil");

        if ($return['cloned']) {
            $sql  = "SELECT value FROM config WHERE name = 'last-sync-url'";

            if ($result = Nano_Db::query($sql)) {
                $url                 = array_pop($result);
                $return['clone-url'] = $url['value'];
            }
        }

        $sql  = "SELECT value FROM config WHERE name = 'last-sync-pw'";

        if ($result = Nano_Db::query($sql)) {
            $password           = array_pop($result);
            $return['clone-pw'] = $password['value'];

            exec($this->getFossilCommand() . " test-obscure " . escapeshellarg($return['clone-pw']), $output, $returnCode);

            if ($returnCode === 0) {
                if (preg_match('/^UNOBSCURE: (.*) -> (.*)$/', $output[1], $matches)) {
                    $return['clone-pw'] = $matches[2];
                }
            }
        }

        Nano_Db::unsetDb();

        if (isset($return)) {
            return $return;
        }

        return false;
    }

    public function updateRepo($repo, $private, $update, $cloned, $password = null)

    {

        if (file_exists("{$this->path}{$repo}.fossil")) {


            $sql = "UPDATE repositories
                       SET private     = :private,
                           auto_update = :auto,
                           cloned      = :cloned
                     WHERE user_id = :id
                       AND name    = :repo";

            $bind = array(
                'private' => $private,
                'auto'    => $update,
                'cloned'  => $cloned,
                'id'      => $this->user['id'],
                'repo'    => $repo,
            );

            if (Nano_Db::execute($sql, $bind)) {
                if ($password) {
                    Nano_Db::setDb("sqlite:{$this->path}{$repo}.fossil");


                    $sql = "SELECT value FROM config WHERE name = 'project-code'";

                    if ($result = Nano_Db::query($sql)) {
                        $code     = array_pop($result);
                        $password = sha1("{$code['value']}/{$this->user['username']}/{$password}");

                        $sql  = "UPDATE user SET pw = :password WHERE login = :user";
                        $bind = array('password' => $password, 'user' => $this->user['username']);
                        Nano_Db::execute($sql, $bind);
                        Nano_Db::unsetDb();
                    }
                }

                return true;
            }
        }




        return false;
    }

    public function remRepo($repo)
    {
        if (file_exists("{$this->path}{$repo}.fossil")) {
            $sql = "DELETE FROM repositories
                     WHERE user_id = :id
                       AND name    = :repo";

            $bind = array('id' => $this->user['id'], 'repo' => $repo);

            if (Nano_Db::execute($sql, $bind)) {
                unlink("{$this->path}{$repo}.fossil");

                return true;
            }
        }


        return false;
    }

    public function remAllRepos()



    {
        if (file_exists("{$this->path}")) {
            $sql = "DELETE FROM repositories
                     WHERE user_id = :id";

            $bind = array('id' => $this->user['id']);

            if (Nano_Db::execute($sql, $bind)) {
                foreach (glob("{$this->path}*.fossil") as $repo) {
                    unlink($repo);

                }



                unlink("{$this->path}repository");
                rmdir("{$this->path}");

                return true;
            }
        }









        return false;
    }
}

















>
>
|
>


>
>

|
<
|
>
>

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|

|
|
|
>

>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>



|







>
>
>
|
>
>
>
>










|
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
|

|
|
|

|
<
<
<
<
|
>
>
>
>
>
>
>
>
|
<
<
>
|
<
<
<
|
>
>
>

<
>
|
>

<
<
>
>

<
<
<
>
>
|
<
|
<
<

<
<
<
<
>
|

>
|
<
>
|
<
<
<

<
<
<
>

>
|
|
|
<
<
<
>
|
<
<
<
|
>
>
>
>
>
|
|
>
>
|
<
<
>
|
>
>
>
>
>
>
|
|
|
>
>

<
>
|
>
>
|
<
|
<
<
>
>
>

<
<
<
>


<
<
<
>
>

|
|
<
>
|

>
>
|
|

>
>
>
>
|
|
|

|

|
<
>
>
|
<
<

<
<
<
>

<
<
<
>
|
>
>
>
|
|
|
<
<
<
>
>

<
<
<
>
>
>
|
>
|

<
<
<
>

|
>
>

|
>

|
|

<
>
>
>
|
<
<
>

<
<
<
>
>
>
|

<
<
>
>
|
|

<
>
>
|
|
>
>
>
>
>
>
|
<
>
|
>
|
<
<
<
|
>
>

|
|

<
<
>
>
>
|
<
<
<

|
<
<
>
>
|
|
<
<
>
|
<
>
|
<
<
<
|
<
<
<
>
>
>
>
|

<
>
|
<
<
|
|

|
|
|

|

|
<
>
>
|
<
<
<

>
>
|
|
|
>

|


|
>
|







<
>
>
>
>
>
>
|
<
<
>
|
>
|
|

|
<
<
>
|
<
<
>
|

|

|
|
|

|
|

<
<
<
<
<
|
<













|
<









<
|



|
|
|




|







|



|








<
<







|
>
|
>
|
>
>
|
|
|
|
|
|

|
|
|
|
|
|
|

|
<
<
>
|
<

|
|
<
|
<
<
<
<
|
<
<
|
|
|
>
>

>
|
|

<
<
<
|
|
|

|

|
<
<
|
|
|
>

|


|
>
>
>
|
<
|
|

|

|
<
<
>
|

>
>
|
|

|
|
|
>
>
>
|
>
>
>
>
>
|
|
|
>
>
>
>
>
>
>
>
>
>
>
>
>
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
135
136
137




138
139
140
141
142
143
144
145
146
147


148
149



150
151
152
153
154

155
156
157
158


159
160
161



162
163
164

165


166




167
168
169
170
171

172
173



174



175
176
177
178
179
180



181
182



183
184
185
186
187
188
189
190
191
192
193


194
195
196
197
198
199
200
201
202
203
204
205
206
207

208
209
210
211
212

213


214
215
216
217



218
219
220



221
222
223
224
225

226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244

245
246
247


248



249
250



251
252
253
254
255
256
257
258



259
260
261



262
263
264
265
266
267
268



269
270
271
272
273
274
275
276
277
278
279
280

281
282
283
284


285
286



287
288
289
290
291


292
293
294
295
296

297
298
299
300
301
302
303
304
305
306
307

308
309
310
311



312
313
314
315
316
317
318


319
320
321
322



323
324


325
326
327
328


329
330

331
332



333



334
335
336
337
338
339

340
341


342
343
344
345
346
347
348
349
350
351

352
353
354



355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375

376
377
378
379
380
381
382


383
384
385
386
387
388
389


390
391


392
393
394
395
396
397
398
399
400
401
402
403





404

405
406
407
408
409
410
411
412
413
414
415
416
417
418

419
420
421
422
423
424
425
426
427

428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459


460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489


490
491

492
493
494

495




496


497
498
499
500
501
502
503
504
505
506



507
508
509
510
511
512
513


514
515
516
517
518
519
520
521
522
523
524
525
526

527
528
529
530
531
532


533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
<?php

class Nano_Fossil
{
    protected $absolute_path_root;
    protected $relative_path_root;
    protected $absolute_path;
    protected $relative_path;
    protected $user;
    protected $workdir;
    protected $use_suid;
    protected $fossil_binary;

    public function __construct($user) {

        $this->repo_dir = $_SERVER['DOCUMENT_ROOT'] . '/../repos';
        $this->absolute_path_root = $this->repo_dir . '/' . $user['username'] . '/';
        $this->absolute_path = $this->absolute_path_root . 'data/';
        $this->user = $user;

        $fossil_config_file = dirname(__FILE__) . '/../config/fossil.cnf';
        $fossil_config = array();
        if (file_exists($fossil_config_file)) {
                $fossil_config = parse_ini_file($fossil_config_file);
        }
        if (isset($fossil_config['use_suid']) && $fossil_config['use_suid'] === '1') {
            $this->use_suid = true;
        } else {
            $this->use_suid = false;
        }

        /*
         * The "suid-fossil" wrapper will either call Fossil directly (if use_suid is false),
         * or invoke a wrapper before calling fossil within a chroot.
         */
        $this->fossil_binary = dirname(__FILE__) . "/../scripts/fossil-as-user/suid-fossil";

        if ($this->use_suid) {
            $this->relative_path_root = '/';
            $this->relative_path = '/data/';
            $this->root_fs = $this->absolute_path_root;
        } else {
            $this->relative_path_root = $this->absolute_path_root;
            $this->relative_path = $this->absolute_path;
            $this->root_fs = '';
        }

        if (!$this->use_suid) {
            $this->workdir = "/tmp/workdir-flint-" . bin2hex(openssl_random_pseudo_bytes(20));

            mkdir($this->workdir);
        }
    }

    public function __destruct() {
        if (!$this->use_suid) {
            system("rm -rf '{$this->workdir}'");
        }
    }

    private function fossil_sql_execute($repo, $sql, $bind = array()) {
        $repo_file = $this->repository_file($repo);
        Nano_Db::setDb("sqlite:{$repo_file}");
        $result = Nano_Db::execute($sql, $bind);
        Nano_Db::unsetDb();
        return($result);
    }

    private function fossil_sql_query($repo, $sql, $bind = array()) {
        $repo_file = $this->repository_file($repo);
        Nano_Db::setDb("sqlite:{$repo_file}");
        $result = Nano_Db::query($sql, $bind);
        Nano_Db::unsetDb();
        return($result);
    }

    private function getFossilCommand($timeout = 0, $cgi = false) {
        $fossil = $this->fossil_binary;

        if ($timeout) {
            $fossil = "timeout {$timeout} {$fossil}";
        }

        $username = escapeshellarg($this->user['username']);

        $cmd = "USER={$username} {$fossil}";

        if (!$this->use_suid) {
            $cmd = "HOME={$this->workdir} {$cmd}";
        }

        $userid = escapeshellarg($this->user['id']);
        $cmd = "FLINT_USERID={$userid} FLINT_USERNAME={$username} {$cmd}";

        if ($cgi) {
            $cmd = "GATEWAY_INTERFACE=1 {$cmd}";
        } else {
            $cmd = "unset GATEWAY_INTERFACE; {$cmd}";
        }

        return $cmd;
    }

    private function repository_file($repo, $absolute = true) {
        if ($absolute) {
            $retval = "{$this->absolute_path}{$repo}.fossil";
        } else {
            $retval = "{$this->relative_path}{$repo}.fossil";
        }

        return $retval;
    }

    private function fossil($repo, $argv, &$output = null, &$return = null, $timeout = 0, $cgi = false) {
        $command = $this->getFossilCommand($timeout, $cgi);

        foreach ($argv as $arg) {
            if ($arg === $this->repository_file($repo)) {
                $arg = $this->repository_file($repo, FALSE);
            }

            $command = $command . " " . escapeshellarg($arg);
        }
        $command = $command . " 2>&1";

        exec($command, $output, $return);
    }

    private function createRepositoryCGI() {
        if (!file_exists($this->absolute_path)) {
            mkdir($this->absolute_path_root);
            mkdir($this->absolute_path);

            $content = "#!{$this->fossil_binary}\ndirectory: ./data/\nnotfound: http://{$_SERVER['SERVER_NAME']}/notfound";
            file_put_contents("{$this->absolute_path_root}repository", $content);
            chmod("{$this->absolute_path_root}repository", 0555);
        }
    }





    private function randomPassword($length = 12) {
        $alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!";
        $alphabet_len = strlen($alphabet);
        $result = "";
        for ($idx = 0; $idx < $length; $idx++) {
            $char_idx = mt_rand(0, $alphabet_len - 1);
            $char = $alphabet[$char_idx];
            $result = $result . $char;
        }


        return $result;
    }




    private function createUser($repo) {
        $username = $this->user['username'];
        $repo_file = $this->repository_file($repo);


        $password = $this->randomPassword(64);

        $this->fossil($repo, array('user', 'new', $username, 'Flint User', $password, '-R', $repo_file), $output, $return);



        if ($return === 0) {
            $this->fossil($repo, array('user', 'capabilities', $username, 's', '-R', $repo_file), $output, $return);




            if ($return === 0) {
                return true;
            }

        }







        return false;
    }

    private function setPassword($repo, $password) {
        if (!$password) {

            $password = $this->randomPassword();
        }







        $this->fossil($repo, array('user', '-R', $this->repository_file($repo), 'password', $this->user['username'], $password), $output, $return);

        if ($return !== 0) {
            return false;
        }




        return $password;
    }




    private function setProjectCode($repo, $projectCode) {
        if ($projectCode) {
            $sql  = "UPDATE config SET value = :code WHERE name = 'project-code'";
            $bind = array('code' => $projectCode);
            $this->fossil_sql_execute($repo, $sql, $bind);
        }
    }

    private function repoConfig($repo) {
        $sql = "UPDATE config SET value = 1 WHERE name = 'localauth'";


        $this->fossil_sql_execute($repo, $sql);
    }

    private function postCreateRepo($repo, $password, $projectCode = null) {
        $this->setProjectCode($repo, $projectCode);
        $this->repoConfig($repo);
        $return = $this->setPassword($repo, $password);

        return $return;
    }

    public function newRepo($repo, $password = null, $private = 0, $projectCode = null, $sha3 = false, &$errorMessage = null) {
        $this->createRepositoryCGI();


        $create_command = array('new');

        if ($sha3 !== true) {
            $create_command[] = '--sha1';
        }




        $repo_file = $this->repository_file($repo);
        if (file_exists($repo_file)) {
            $errorMessage = 'File already exists';




            return false;
        }




        array_push($create_command, '-A', $this->user['username'], $repo_file);
        $this->fossil($repo, $create_command, $output, $return);

        if ($return !== 0) {
            if (file_exists($repo_file)) {

                unlink($repo_file);
            }

            $errorMessage = 'fossil new failed: '. join("\n", $output);

            return false;
        }

        /* Install default configuration */
        /** XXX:TODO: This won't work within the chroot **/
        $this->fossil($repo, array('configuration', 'import', '-R', $repo_file, $_SERVER['DOCUMENT_ROOT'] . "/../config/fossil-default.cnf"));

        $sql = "INSERT INTO repositories
                       (user_id, name, private, cloned, auto_update)
                VALUES (:id, :name, :private, 0, 0)";

        $bind = array('id' => $this->user['id'], 'name' => $repo, 'private' => $private);

        if (!Nano_Db::execute($sql, $bind)) {

            if (file_exists($repo_file)) {
                unlink($repo_file);
            }






            $errorMessage = 'Internal Error: DB Insert failed';




            return false;
        }

        $return = $this->postCreateRepo($repo, $password, $projectCode);

        return $return;
    }




    public function cloneRepo($repo, $password = null, $url, $private = 0, $update = 0, &$errorMessage = null) {
        $this->createRepositoryCGI();




        $repo_file = $this->repository_file($repo);
        if (file_exists($repo_file)) {
            $errorMessage = 'File already exists';

            return false;
        }




        $this->fossil($repo, array('clone', '-A', $this->user['username'], $url, $repo_file), $output, $return, 3600);

        if ($return !== 0) {
            if (file_exists($repo_file)) {
                unlink($repo_file);
            }

            $errorMessage = 'Clone failed: ' . join("\n", $output);

            return false;
        }


        $sql = "INSERT INTO repositories
                       (user_id, name, private, cloned, auto_update)
                VALUES (:id, :name, :private, 1, :auto)";



        $bind = array('id' => $this->user['id'], 'name' => $repo, 'private' => $private, 'auto' => $update);




        if (!Nano_Db::execute($sql, $bind)) {
            if (file_exists($repo_file)) {
                unlink($repo_file);
            }



            $errorMessage = 'Internal Error: DB Insert failed';

            return false;
        }


        $return = $this->postCreateRepo($repo, $password);

        return $return;
    }

    public function uploadRepo($repo, $password, $private = 0, array $file, &$errorMessage = null) {
        $this->createRepositoryCGI();

        $repo_file = $this->repository_file($repo);

        if (file_exists($repo_file)) {

            $errorMessage = 'File already exists';

            return false;
        }




        if (!@move_uploaded_file($file['tmp_name'], $repo_file)) {
            $errorMessage = 'Internal Error: Upload failed';

            return false;
        }



        $this->fossil($repo, array('config', '-R', $repo_file, 'export', 'project', '/tmp/config'), $output, $return);
        if (file_exists($this->root_fs . '/tmp/config')) {
            unlink($this->root_fs . '/tmp/config');
        }




        if ($return !== 0) {


            if (file_exists($repo_file)) {
                unlink($repo_file);
            }



            $errorMessage = 'Invalid repository';


            return false;
        }







        $return = $this->createUser($repo);
        if ($return === false) {
            if (file_exists($repo_file)) {
                unlink($repo_file);
            }


            $errorMessage = 'Failed to create new user';



            return false;
        }

        $sql = "INSERT INTO repositories
                       (user_id, name, private, cloned, auto_update)
                VALUES (:id, :name, :private, 0, 0)";

        $bind = array('id' => $this->user['id'], 'name' => $repo, 'private' => $private);

        if (!Nano_Db::execute($sql, $bind)) {

            if (file_exists($repo_file)) {
                unlink($repo_file);
            }




            $errorMessage = 'Internal Error: DB Insert failed';

            return false;
        }

        $return = $this->postCreateRepo($repo, $password);

        return $return;
    }

    public function pullRepo($repo, $url = '', &$outputstr = null) {
        $repo_file = $this->repository_file($repo);

        if ($url != '') {
            if (file_exists($url) || preg_match('/:\/\//', $url) == 0) {
                $outputstr = "Invalid URL";
                return false;
            }
        }


        if (!file_exists($repo_file)) {
            $outputstr = "Invalid repository";

            return false;
        }

        # Ensure that no non-default SSH command can be used for a pull


        $this->fossil($repo, array('unset', 'ssh-command', '-R', $repo_file), $output, $return);
        if ($return !== 0) {
            $outputstr = "Failed to unset ssh-command: " . join("\n", $output);
            return false;
        }

        if ($url == '') {


            $this->fossil($repo, array('pull', '-R', $repo_file), $output, $return, 3600);
        } else {


            $this->fossil($repo, array('pull', '-R', $repo_file, $url), $output, $return, 3600);
        }

        $outputstr = join("\n", $output);

        if ($return !== 0) {
            return false;
        }

        return true;
    }






    public function getRepos() {

        $sql = "SELECT *
                  FROM repositories
                 WHERE user_id = :id";

        $bind = array('id' => $this->user['id']);

        if ($result = Nano_Db::query($sql, $bind)) {
            return $result;
        }

        return false;
    }

    public function getRepoById($id) {

        $sql = "SELECT *
                  FROM repositories
                 WHERE user_id = :user
                   AND id = :id";

        $bind = array('user' => $this->user['id'], 'id' => $id);

        if ($result = Nano_Db::query($sql, $bind)) {
            $return = array_pop($result);

        } else {
            return false;
        }

        $repo = $return['name'];
        $repo_file = $this->repository_file($repo);
        $return['repo-file'] = $repo_file;

        if ($return['cloned']) {
            $sql  = "SELECT value FROM config WHERE name = 'last-sync-url'";

            if ($result = $this->fossil_sql_query($repo, $sql)) {
                $url                 = array_pop($result);
                $return['clone-url'] = $url['value'];
            }
        }

        $sql  = "SELECT value FROM config WHERE name = 'last-sync-pw'";

        if ($result = $this->fossil_sql_query($repo, $sql)) {
            $password           = array_pop($result);
            $return['clone-pw'] = $password['value'];

            $this->fossil($repo, array('test-obscure', $return['clone-pw']), $output, $returnCode);

            if ($returnCode === 0) {
                if (preg_match('/^UNOBSCURE: (.*) -> (.*)$/', $output[1], $matches)) {
                    $return['clone-pw'] = $matches[2];
                }
            }
        }



        if (isset($return)) {
            return $return;
        }

        return false;
    }

    public function updateRepo($repo, $private, $update, $cloned, $password = null) {
        $repo_file = $this->repository_file($repo);

        if (!file_exists($repo_file)) {
            return false;
        }

        $sql = "UPDATE repositories
                   SET private     = :private,
                       auto_update = :auto,
                       cloned      = :cloned
                 WHERE user_id = :id
                   AND name    = :repo";

        $bind = array(
            'private' => $private,
            'auto'    => $update,
            'cloned'  => $cloned,
            'id'      => $this->user['id'],
            'repo'    => $repo,
        );

        if (!Nano_Db::execute($sql, $bind)) {


            return false;
        }


        if ($password) {
            $this->setPassword($repo, $password);

        }







        return true;
    }

    public function remRepo($repo) {
        $repo_file = $this->repository_file($repo);

        if (!file_exists($repo_file)) {
            return false;
        }




        $sql = "DELETE FROM repositories
                 WHERE user_id = :id
                   AND name    = :repo";

        $bind = array('id' => $this->user['id'], 'repo' => $repo);

        if (!Nano_Db::execute($sql, $bind)) {


            return false;
        }

        unlink($repo_file);

        return true;
    }

    public function remAllRepos() {
        if (!file_exists("{$this->absolute_path}")) {
            return false;
        }


        $sql = "DELETE FROM repositories
                 WHERE user_id = :id";

        $bind = array('id' => $this->user['id']);

        if (!Nano_Db::execute($sql, $bind)) {


            return false;
        }

        system('rm -f ' . escapeshellarg($this->absolute_path) . '/*.fossil');

        unlink("{$this->absolute_path_root}repository");
        rmdir("{$this->absolute_path_root}");

        return true;
    }

    public function rebuildAllRepos() {
        if (!file_exists("{$this->absolute_path}")) {
            return false;
        }

        $sql = "SELECT name FROM repositories WHERE user_id = :id";
        $bind = array('id' => $this->user['id']);
        $result = Nano_Db::query($sql, $bind);
        if ($result === false) {
            return false;
        }

        foreach ($result as $repo_info) {
            $repo = $repo_info['name'];
            $repo_file = $this->repository_file($repo);
            $this->fossil($repo, array('rebuild', $repo_file, '--quiet', '--wal'), $output, $return, 7200);
            if ($return !== 0) {
                $outputstr = join("\n", $output);
                error_log("Failed while rebuilding {$repo_file}: {$outputstr}");
            }
        }

        return true;
    }
}

Changes to public/secure/index.php.

31
32
33
34
35
36
37
38
39
40
41
42

if (isset($_SESSION['pull'])) {
    $view->pull = $_SESSION['pull'];
    unset($_SESSION['pull']);
}

if (isset($_SESSION['update'])) {
    $view->pull = $_SESSION['update'];
    unset($_SESSION['update']);
}

$view->dispatch();







|




31
32
33
34
35
36
37
38
39
40
41
42

if (isset($_SESSION['pull'])) {
    $view->pull = $_SESSION['pull'];
    unset($_SESSION['pull']);
}

if (isset($_SESSION['update'])) {
    $view->pull = array('name' => $_SESSION['update'], 'success' => true);
    unset($_SESSION['update']);
}

$view->dispatch();

Changes to public/secure/presentation/index.tpl.

1
2
3
4
5

6




7
8
9
10
11
12
13
<? if (isset($this->new)): ?>
<p class="success">Your account was created and you are now logged in.</p>
<? endif ?>

<? if (isset($this->pull)): ?>

<p class="success"><?= $this->pull ?> was successfully updated.</p>




<? endif ?>

<h3>Public Repositories</h3>
<? if (count($this->public)): ?>
    <ul>
    <? foreach ($this->public as $repo): ?>
        <li><a href="/user/<?= $this->user['username'] ?>/repository/<?= $repo['name'] ?>"><?= $repo['name'] ?></a> - <? if ($repo['cloned']): ?><a href="/secure/repository/pull/id/<?= $repo['id'] ?>">Pull</a> | <? endif ?><a href="/secure/repository/edit/id/<?= $repo['id'] ?>">Edit</a> | <a href="/secure/repository/remove/id/<?= $repo['id'] ?>" class="remove">Remove</a> | <a href="/secure/repository/help_clone/id/<?= $repo['id'] ?>">How to Clone</a></li>





>
|
>
>
>
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<? if (isset($this->new)): ?>
<p class="success">Your account was created and you are now logged in.</p>
<? endif ?>

<? if (isset($this->pull)): ?>
<? if ($this->pull['success']) { ?>
<p class="success"><?= $this->pull['name'] ?> was successfully updated.</p>
<? } else { ?>
<p class="failure"><?= $this->pull['name'] ?> failed to be updated.</p>
Output: <pre><?= $this->pull['output'] ?></pre>
<? } ?>
<? endif ?>

<h3>Public Repositories</h3>
<? if (count($this->public)): ?>
    <ul>
    <? foreach ($this->public as $repo): ?>
        <li><a href="/user/<?= $this->user['username'] ?>/repository/<?= $repo['name'] ?>"><?= $repo['name'] ?></a> - <? if ($repo['cloned']): ?><a href="/secure/repository/pull/id/<?= $repo['id'] ?>">Pull</a> | <? endif ?><a href="/secure/repository/edit/id/<?= $repo['id'] ?>">Edit</a> | <a href="/secure/repository/remove/id/<?= $repo['id'] ?>" class="remove">Remove</a> | <a href="/secure/repository/help_clone/id/<?= $repo['id'] ?>">How to Clone</a></li>

Changes to public/secure/repository/create.php.

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
..
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81

82
83
84
85
86
87
88
..
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

    if ($validation->validate($_POST, $rules)) {
        $user   = Nano_Session::user();
        $fossil = new Nano_Fossil($user);

        if (isset($_POST['repository-password']) && !empty($_POST['repository-password'])) {
            $password = $_POST['repository-password'];
        }
        else {
            $password = null;
        }

        $private = isset($_POST['private']) ? '1' : '0';

        if (isset($_POST['project-code']) && !empty($_POST['project-code'])) {
            $projectCode = $_POST['project-code'];
        } else {
            $projectCode = null;
        }

        $sha3 = isset($_POST['sha3']);

        if ($result = $fossil->newRepo($_POST['repository-name'], $password, $private, $projectCode, $sha3)) {
            $view->user     = $user;
            $view->name     = $_POST['repository-name'];
            $view->private  = $private;
            $view->password = $result;
            $view->success  = true;
        }
        else {
            $view->error = true;

        }
    }
    else {
        Nano_Variable::set('validationErrors', $validation->errors());
    }
}

if (isset($_GET['type']) && $_GET['type'] == 'clone' && $_POST) {
    $validation = new Nano_Validation();

................................................................................
            $password = null;
        }

        $private = isset($_POST['private']) ? '1' : '0';
        $update  = isset($_POST['auto-update']) ? '1' : '0';

        if ($result = $fossil->cloneRepo($_POST['repository-name'], $password, $_POST['clone-url'],
                                         $private, $update)) {
            $view->user     = $user;
            $view->name     = $_POST['repository-name'];
            $view->private  = $private;
            $view->update   = $update;
            $view->password = $result;
            $view->success  = true;
        }
        else {
            $view->error = true;

        }
    }
    else {
        Nano_Variable::set('validationErrors', $validation->errors());
    }
}

................................................................................
        }
        else {
            $user   = Nano_Session::user();
            $fossil = new Nano_Fossil($user);

            $private = isset($_POST['private']) ? '1' : '0';

            if ($fossil->uploadRepo($_POST['repository-name'], $_POST['repository-password'], $private, $_FILES['upload'])) {
                $view->user     = $user;
                $view->name     = $_POST['repository-name'];
                $view->private  = $private;
                $view->password = 'sha1';
                $view->success  = true;
            }
            else {
                $view->error = true;

            }
        }
    }
    else {
        Nano_Variable::set('validationErrors', $validation->errors());
    }
}

$view->dispatch();







<
|













|





<
|

>

<
|







 







|









>







 







|








>









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
..
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
..
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

    if ($validation->validate($_POST, $rules)) {
        $user   = Nano_Session::user();
        $fossil = new Nano_Fossil($user);

        if (isset($_POST['repository-password']) && !empty($_POST['repository-password'])) {
            $password = $_POST['repository-password'];

        } else {
            $password = null;
        }

        $private = isset($_POST['private']) ? '1' : '0';

        if (isset($_POST['project-code']) && !empty($_POST['project-code'])) {
            $projectCode = $_POST['project-code'];
        } else {
            $projectCode = null;
        }

        $sha3 = isset($_POST['sha3']);

        if ($result = $fossil->newRepo($_POST['repository-name'], $password, $private, $projectCode, $sha3, $errorMessage)) {
            $view->user     = $user;
            $view->name     = $_POST['repository-name'];
            $view->private  = $private;
            $view->password = $result;
            $view->success  = true;

        } else {
            $view->error = true;
            $view->errorMessage = $errorMessage;
        }

    } else {
        Nano_Variable::set('validationErrors', $validation->errors());
    }
}

if (isset($_GET['type']) && $_GET['type'] == 'clone' && $_POST) {
    $validation = new Nano_Validation();

................................................................................
            $password = null;
        }

        $private = isset($_POST['private']) ? '1' : '0';
        $update  = isset($_POST['auto-update']) ? '1' : '0';

        if ($result = $fossil->cloneRepo($_POST['repository-name'], $password, $_POST['clone-url'],
                                         $private, $update, $errorMessage)) {
            $view->user     = $user;
            $view->name     = $_POST['repository-name'];
            $view->private  = $private;
            $view->update   = $update;
            $view->password = $result;
            $view->success  = true;
        }
        else {
            $view->error = true;
            $view->errorMessage = $errorMessage;
        }
    }
    else {
        Nano_Variable::set('validationErrors', $validation->errors());
    }
}

................................................................................
        }
        else {
            $user   = Nano_Session::user();
            $fossil = new Nano_Fossil($user);

            $private = isset($_POST['private']) ? '1' : '0';

            if ($fossil->uploadRepo($_POST['repository-name'], $_POST['repository-password'], $private, $_FILES['upload'], $errorMessage)) {
                $view->user     = $user;
                $view->name     = $_POST['repository-name'];
                $view->private  = $private;
                $view->password = 'sha1';
                $view->success  = true;
            }
            else {
                $view->error = true;
                $view->errorMessage = $errorMessage;
            }
        }
    }
    else {
        Nano_Variable::set('validationErrors', $validation->errors());
    }
}

$view->dispatch();

Changes to public/secure/repository/presentation/create.tpl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
..
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
..
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
<? if (isset($this->success)): ?>
<p>Your new repository, <a href="/user/<?= $this->user['username'] ?>/repository/<?= $this->name ?>"><?= $this->name ?></a>, was successfully created<? if ($this->update): ?> and set to pull in changes on a periodic basis<? endif ?>!</p>
<p>Remember since fossil is an all in one solution you are required to setup repository specific permissions.<? if ($this->private): ?> While your repository won't show up on your public user page you still need to go in and lock it down yourself.<? endif ?> The default user for your new repository is the same as your flint username, however the password is <? if ($this->password == 'sha1'): ?>user set<? else: ?><?= $this->password ?><? endif ?>, we recommend you log in and change this to something else.</p>
<ul>
    <li>Username: <?= $this->user['username'] ?></li>
    <li>Password: <? if ($this->password == 'sha1'): ?>User set<? else: ?><?= $this->password ?><? endif ?></li>
    <li>URL: http(s)://<?= $_SERVER['SERVER_NAME'] ?>/user/<?= $this->user['username'] ?>/repository/<?= $this->name ?></li>
</ul>
<p><a href="/secure/">Return to dashboard</a></p>
<? else: ?>
<? if ((isset($_GET['type']) && $_GET['type'] == 'new') || !isset($_GET['type'])): ?>
<p>Please fill out the form below to create a new repository. If a password is not set a random one will be created for you.</p>

<? if (isset($this->error)): ?>
<p class="error">Something failed during the creation process please try again.</p>
<? endif ?>

<? if (isset($this->max)): ?>
<p class="error">You are currently limited to 10 repositories at a time.</p>
<? endif ?>

<form action="/secure/repository/create/type/new/" method="post">
................................................................................
    </p>
</form>
<? endif ?>
<? if (isset($_GET['type']) && $_GET['type'] == 'clone'): ?>
<p>Please fill out the form below to clone an existing repository. If a password is not set a random one will be created for you.</p>

<? if (isset($this->error)): ?>
<p class="error">Something failed during the creation process please try again.</p>
<? endif ?>

<? if (isset($this->max)): ?>
<p class="error">You are currently limited to 10 repositories at a time.</p>
<? endif ?>

<form action="/secure/repository/create/type/clone/" method="post">
................................................................................
    </p>
</form>
<? endif ?>
<? if (isset($_GET['type']) && $_GET['type'] == 'upload'): ?>
<p>Please fill out the form below to upload an existing repository. A new super-user will be created that matches your flint username and the password you provide below. Limit 8M in size. If your repository is larger than this, create a new empty project and push to it instead.</p>

<? if (isset($this->error)): ?>
<p class="error">Something failed during the creation process please try again.</p>
<? endif ?>

<? if (isset($this->max)): ?>
<p class="error">You are currently limited to 10 repositories at a time.</p>
<? endif ?>

<form action="/secure/repository/create/type/upload/" method="post" enctype="multipart/form-data">


|


|








|







 







|







 







|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
..
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
..
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
<? if (isset($this->success)): ?>
<p>Your new repository, <a href="/user/<?= $this->user['username'] ?>/repository/<?= $this->name ?>"><?= $this->name ?></a>, was successfully created<? if ($this->update): ?> and set to pull in changes on a periodic basis<? endif ?>!</p>
<p>Remember since fossil is an all in one solution you are required to setup repository specific permissions.<? if ($this->private): ?> While your repository won't show up on your public user page you still need to go in and lock it down yourself.<? endif ?> The default user for your new repository is the same as your flint username, however the password is <? if ($this->password == '@@user_set@@'): ?>user set<? else: ?><?= $this->password ?><? endif ?>, we recommend you log in and change this to something else.</p>
<ul>
    <li>Username: <?= $this->user['username'] ?></li>
    <li>Password: <? if ($this->password == '@@user_set@@'): ?>User set<? else: ?><?= $this->password ?><? endif ?></li>
    <li>URL: http(s)://<?= $_SERVER['SERVER_NAME'] ?>/user/<?= $this->user['username'] ?>/repository/<?= $this->name ?></li>
</ul>
<p><a href="/secure/">Return to dashboard</a></p>
<? else: ?>
<? if ((isset($_GET['type']) && $_GET['type'] == 'new') || !isset($_GET['type'])): ?>
<p>Please fill out the form below to create a new repository. If a password is not set a random one will be created for you.</p>

<? if (isset($this->error)): ?>
<p class="error">Something failed during the creation process please try again.  Error: <pre><?= $this->errorMessage ?></pre></p>
<? endif ?>

<? if (isset($this->max)): ?>
<p class="error">You are currently limited to 10 repositories at a time.</p>
<? endif ?>

<form action="/secure/repository/create/type/new/" method="post">
................................................................................
    </p>
</form>
<? endif ?>
<? if (isset($_GET['type']) && $_GET['type'] == 'clone'): ?>
<p>Please fill out the form below to clone an existing repository. If a password is not set a random one will be created for you.</p>

<? if (isset($this->error)): ?>
<p class="error">Something failed during the creation process please try again:  Error: <pre><?= $this->errorMessage ?></pre></p>
<? endif ?>

<? if (isset($this->max)): ?>
<p class="error">You are currently limited to 10 repositories at a time.</p>
<? endif ?>

<form action="/secure/repository/create/type/clone/" method="post">
................................................................................
    </p>
</form>
<? endif ?>
<? if (isset($_GET['type']) && $_GET['type'] == 'upload'): ?>
<p>Please fill out the form below to upload an existing repository. A new super-user will be created that matches your flint username and the password you provide below. Limit 8M in size. If your repository is larger than this, create a new empty project and push to it instead.</p>

<? if (isset($this->error)): ?>
<p class="error">Something failed during the creation process please try again.  Error: <pre><?= $this->errorMessage ?></pre></p>
<? endif ?>

<? if (isset($this->max)): ?>
<p class="error">You are currently limited to 10 repositories at a time.</p>
<? endif ?>

<form action="/secure/repository/create/type/upload/" method="post" enctype="multipart/form-data">

Changes to public/secure/repository/pull.php.

1
2
3
4
5
6
7
8




9
10
11
12
<?php

$user   = Nano_Session::user();
$fossil = new Nano_Fossil($user);

if ($repo = $fossil->getRepoById($_GET['id'])) {
    $fossil->pullRepo($repo['name']);
    $_SESSION['pull'] = $repo['name'];




}

header('Location: /secure/');
die();






|
|
>
>
>
>




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php

$user   = Nano_Session::user();
$fossil = new Nano_Fossil($user);

if ($repo = $fossil->getRepoById($_GET['id'])) {
    $success = $fossil->pullRepo($repo['name'], '', $output);
    $_SESSION['pull'] = array(
        'name' => $repo['name'],
        'success' => $success,
        'output' => $output
    );
}

header('Location: /secure/');
die();

Added scripts/fossil-as-user/Makefile.









































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
all: suid-fossil secure-wrap

filter.h: generate-seccomp-filter filter.seccomp Makefile
	./generate-seccomp-filter filter.seccomp i386 "" x86_64 "" > filter.h.new
	mv filter.h.new filter.h

secure-wrap: secure-wrap.c filter.h Makefile
	gcc  -W -Wall -Wextra -Wno-type-limits -ansi -pedantic-errors -Werror -fPIC -DPIC -pie -fPIE -fstack-protector-all -O2 -D_FORTIFY_SOURCE=2 -fno-strict-overflow -o secure-wrap secure-wrap.c
	sudo chown root:root secure-wrap
	sudo chmod +s secure-wrap

clean:
	rm -f filter.h secure-wrap

distclean: clean

mrproper: distclean

.PHONY: all clean distclean
.SUFFIXES:

Added scripts/fossil-as-user/filter.seccomp.















































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
i386 {
	return kill
}

x86_64 {
	if {$nr eq "socket"} {
		if {$args(0) ni {PF_LOCAL PF_INET PF_INET6}} {
			return errno EINVAL
		}
	}

	if {$nr in "setpgid"} {
		if {$args(0) == $args(1)} {
			return allow
		} else {
			return errno EACCES
		}
	}

	if {$nr == "kill"} {
		if {$args(1) == 0} {
			return allow
		}
	}

	if {$nr in {
	    bind
	    socket
	    setsockopt
	    connect
	    select
	    poll
	    sendto
	    recvfrom
	    readv
	    writev
	    madvise
	    tgkill
	    futex
	    access
	    arch_prctl
	    brk
	    chdir
	    fchdir
	    close
	    execve
	    exit_group
	    fstat
	    getrlimit
	    getuid
	    ioctl
	    lseek
	    mmap
	    mprotect
	    munmap
	    open
	    fcntl
	    read
	    pread64
	    pwrite64
	    getdents
	    readlink
	    rt_sigaction
	    set_tid_address
	    uname
	    write
	    pipe
	    nanosleep
	    getcwd
	    clone
	    fork
	    vfork
	    stat
	    lstat
	    statfs
	    rename
	    mkdir
	    getpid
	    wait4
	    exit
	    mkdirat
	    mknodat
	    fchownat
	    futimesat
	    newfstatat
	    unlinkat
	    unlink
	    renameat
	    linkat
	    symlinkat
	    readlinkat
	    fchmodat
	    faccessat
	    set_robust_list
	    rt_sigprocmask
	    restart_syscall
	    openat
	    getgid
	    geteuid
	    getegid
	    getppid
	    getpgrp
	    dup
	    dup2
	    dup3
	    rt_sigreturn
	    prlimit64
	    setrlimit
	    getrusage
	    fsync
	    ftruncate
	    gettid
	    setsid
	}} {
		return allow
	}

	return errno ENOSYS
}

Added scripts/fossil-as-user/generate-seccomp-filter.















































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
#! /usr/bin/env tclsh

# ----
namespace eval ::seccomp_bpf {}

if {![info exists ::seccomp_bpf::_handle_index]} {
	set ::seccomp_bpf::_handle_index -1
}

if {![info exists ::seccomp_bpf::_platform_data(x86_64)]} {
	set ::seccomp_bpf::_platform_data(x86_64) {
#
# 64-bit system call numbers and entry vectors
#
# The format is:
# <number> <abi> <name> <entry point>
#
# The __x64_sys_*() stubs are created on-the-fly for sys_*() system calls
#
# The abi is "common", "64" or "x32" for this file.
#
0	common	read			__x64_sys_read
1	common	write			__x64_sys_write
2	common	open			__x64_sys_open
3	common	close			__x64_sys_close
4	common	stat			__x64_sys_newstat
5	common	fstat			__x64_sys_newfstat
6	common	lstat			__x64_sys_newlstat
7	common	poll			__x64_sys_poll
8	common	lseek			__x64_sys_lseek
9	common	mmap			__x64_sys_mmap
10	common	mprotect		__x64_sys_mprotect
11	common	munmap			__x64_sys_munmap
12	common	brk			__x64_sys_brk
13	64	rt_sigaction		__x64_sys_rt_sigaction
14	common	rt_sigprocmask		__x64_sys_rt_sigprocmask
15	64	rt_sigreturn		__x64_sys_rt_sigreturn/ptregs
16	64	ioctl			__x64_sys_ioctl
17	common	pread64			__x64_sys_pread64
18	common	pwrite64		__x64_sys_pwrite64
19	64	readv			__x64_sys_readv
20	64	writev			__x64_sys_writev
21	common	access			__x64_sys_access
22	common	pipe			__x64_sys_pipe
23	common	select			__x64_sys_select
24	common	sched_yield		__x64_sys_sched_yield
25	common	mremap			__x64_sys_mremap
26	common	msync			__x64_sys_msync
27	common	mincore			__x64_sys_mincore
28	common	madvise			__x64_sys_madvise
29	common	shmget			__x64_sys_shmget
30	common	shmat			__x64_sys_shmat
31	common	shmctl			__x64_sys_shmctl
32	common	dup			__x64_sys_dup
33	common	dup2			__x64_sys_dup2
34	common	pause			__x64_sys_pause
35	common	nanosleep		__x64_sys_nanosleep
36	common	getitimer		__x64_sys_getitimer
37	common	alarm			__x64_sys_alarm
38	common	setitimer		__x64_sys_setitimer
39	common	getpid			__x64_sys_getpid
40	common	sendfile		__x64_sys_sendfile64
41	common	socket			__x64_sys_socket
42	common	connect			__x64_sys_connect
43	common	accept			__x64_sys_accept
44	common	sendto			__x64_sys_sendto
45	64	recvfrom		__x64_sys_recvfrom
46	64	sendmsg			__x64_sys_sendmsg
47	64	recvmsg			__x64_sys_recvmsg
48	common	shutdown		__x64_sys_shutdown
49	common	bind			__x64_sys_bind
50	common	listen			__x64_sys_listen
51	common	getsockname		__x64_sys_getsockname
52	common	getpeername		__x64_sys_getpeername
53	common	socketpair		__x64_sys_socketpair
54	64	setsockopt		__x64_sys_setsockopt
55	64	getsockopt		__x64_sys_getsockopt
56	common	clone			__x64_sys_clone/ptregs
57	common	fork			__x64_sys_fork/ptregs
58	common	vfork			__x64_sys_vfork/ptregs
59	64	execve			__x64_sys_execve/ptregs
60	common	exit			__x64_sys_exit
61	common	wait4			__x64_sys_wait4
62	common	kill			__x64_sys_kill
63	common	uname			__x64_sys_newuname
64	common	semget			__x64_sys_semget
65	common	semop			__x64_sys_semop
66	common	semctl			__x64_sys_semctl
67	common	shmdt			__x64_sys_shmdt
68	common	msgget			__x64_sys_msgget
69	common	msgsnd			__x64_sys_msgsnd
70	common	msgrcv			__x64_sys_msgrcv
71	common	msgctl			__x64_sys_msgctl
72	common	fcntl			__x64_sys_fcntl
73	common	flock			__x64_sys_flock
74	common	fsync			__x64_sys_fsync
75	common	fdatasync		__x64_sys_fdatasync
76	common	truncate		__x64_sys_truncate
77	common	ftruncate		__x64_sys_ftruncate
78	common	getdents		__x64_sys_getdents
79	common	getcwd			__x64_sys_getcwd
80	common	chdir			__x64_sys_chdir
81	common	fchdir			__x64_sys_fchdir
82	common	rename			__x64_sys_rename
83	common	mkdir			__x64_sys_mkdir
84	common	rmdir			__x64_sys_rmdir
85	common	creat			__x64_sys_creat
86	common	link			__x64_sys_link
87	common	unlink			__x64_sys_unlink
88	common	symlink			__x64_sys_symlink
89	common	readlink		__x64_sys_readlink
90	common	chmod			__x64_sys_chmod
91	common	fchmod			__x64_sys_fchmod
92	common	chown			__x64_sys_chown
93	common	fchown			__x64_sys_fchown
94	common	lchown			__x64_sys_lchown
95	common	umask			__x64_sys_umask
96	common	gettimeofday		__x64_sys_gettimeofday
97	common	getrlimit		__x64_sys_getrlimit
98	common	getrusage		__x64_sys_getrusage
99	common	sysinfo			__x64_sys_sysinfo
100	common	times			__x64_sys_times
101	64	ptrace			__x64_sys_ptrace
102	common	getuid			__x64_sys_getuid
103	common	syslog			__x64_sys_syslog
104	common	getgid			__x64_sys_getgid
105	common	setuid			__x64_sys_setuid
106	common	setgid			__x64_sys_setgid
107	common	geteuid			__x64_sys_geteuid
108	common	getegid			__x64_sys_getegid
109	common	setpgid			__x64_sys_setpgid
110	common	getppid			__x64_sys_getppid
111	common	getpgrp			__x64_sys_getpgrp
112	common	setsid			__x64_sys_setsid
113	common	setreuid		__x64_sys_setreuid
114	common	setregid		__x64_sys_setregid
115	common	getgroups		__x64_sys_getgroups
116	common	setgroups		__x64_sys_setgroups
117	common	setresuid		__x64_sys_setresuid
118	common	getresuid		__x64_sys_getresuid
119	common	setresgid		__x64_sys_setresgid
120	common	getresgid		__x64_sys_getresgid
121	common	getpgid			__x64_sys_getpgid
122	common	setfsuid		__x64_sys_setfsuid
123	common	setfsgid		__x64_sys_setfsgid
124	common	getsid			__x64_sys_getsid
125	common	capget			__x64_sys_capget
126	common	capset			__x64_sys_capset
127	64	rt_sigpending		__x64_sys_rt_sigpending
128	64	rt_sigtimedwait		__x64_sys_rt_sigtimedwait
129	64	rt_sigqueueinfo		__x64_sys_rt_sigqueueinfo
130	common	rt_sigsuspend		__x64_sys_rt_sigsuspend
131	64	sigaltstack		__x64_sys_sigaltstack
132	common	utime			__x64_sys_utime
133	common	mknod			__x64_sys_mknod
134	64	uselib
135	common	personality		__x64_sys_personality
136	common	ustat			__x64_sys_ustat
137	common	statfs			__x64_sys_statfs
138	common	fstatfs			__x64_sys_fstatfs
139	common	sysfs			__x64_sys_sysfs
140	common	getpriority		__x64_sys_getpriority
141	common	setpriority		__x64_sys_setpriority
142	common	sched_setparam		__x64_sys_sched_setparam
143	common	sched_getparam		__x64_sys_sched_getparam
144	common	sched_setscheduler	__x64_sys_sched_setscheduler
145	common	sched_getscheduler	__x64_sys_sched_getscheduler
146	common	sched_get_priority_max	__x64_sys_sched_get_priority_max
147	common	sched_get_priority_min	__x64_sys_sched_get_priority_min
148	common	sched_rr_get_interval	__x64_sys_sched_rr_get_interval
149	common	mlock			__x64_sys_mlock
150	common	munlock			__x64_sys_munlock
151	common	mlockall		__x64_sys_mlockall
152	common	munlockall		__x64_sys_munlockall
153	common	vhangup			__x64_sys_vhangup
154	common	modify_ldt		__x64_sys_modify_ldt
155	common	pivot_root		__x64_sys_pivot_root
156	64	_sysctl			__x64_sys_sysctl
157	common	prctl			__x64_sys_prctl
158	common	arch_prctl		__x64_sys_arch_prctl
159	common	adjtimex		__x64_sys_adjtimex
160	common	setrlimit		__x64_sys_setrlimit
161	common	chroot			__x64_sys_chroot
162	common	sync			__x64_sys_sync
163	common	acct			__x64_sys_acct
164	common	settimeofday		__x64_sys_settimeofday
165	common	mount			__x64_sys_mount
166	common	umount2			__x64_sys_umount
167	common	swapon			__x64_sys_swapon
168	common	swapoff			__x64_sys_swapoff
169	common	reboot			__x64_sys_reboot
170	common	sethostname		__x64_sys_sethostname
171	common	setdomainname		__x64_sys_setdomainname
172	common	iopl			__x64_sys_iopl/ptregs
173	common	ioperm			__x64_sys_ioperm
174	64	create_module
175	common	init_module		__x64_sys_init_module
176	common	delete_module		__x64_sys_delete_module
177	64	get_kernel_syms
178	64	query_module
179	common	quotactl		__x64_sys_quotactl
180	64	nfsservctl
181	common	getpmsg
182	common	putpmsg
183	common	afs_syscall
184	common	tuxcall
185	common	security
186	common	gettid			__x64_sys_gettid
187	common	readahead		__x64_sys_readahead
188	common	setxattr		__x64_sys_setxattr
189	common	lsetxattr		__x64_sys_lsetxattr
190	common	fsetxattr		__x64_sys_fsetxattr
191	common	getxattr		__x64_sys_getxattr
192	common	lgetxattr		__x64_sys_lgetxattr
193	common	fgetxattr		__x64_sys_fgetxattr
194	common	listxattr		__x64_sys_listxattr
195	common	llistxattr		__x64_sys_llistxattr
196	common	flistxattr		__x64_sys_flistxattr
197	common	removexattr		__x64_sys_removexattr
198	common	lremovexattr		__x64_sys_lremovexattr
199	common	fremovexattr		__x64_sys_fremovexattr
200	common	tkill			__x64_sys_tkill
201	common	time			__x64_sys_time
202	common	futex			__x64_sys_futex
203	common	sched_setaffinity	__x64_sys_sched_setaffinity
204	common	sched_getaffinity	__x64_sys_sched_getaffinity
205	64	set_thread_area
206	64	io_setup		__x64_sys_io_setup
207	common	io_destroy		__x64_sys_io_destroy
208	common	io_getevents		__x64_sys_io_getevents
209	64	io_submit		__x64_sys_io_submit
210	common	io_cancel		__x64_sys_io_cancel
211	64	get_thread_area
212	common	lookup_dcookie		__x64_sys_lookup_dcookie
213	common	epoll_create		__x64_sys_epoll_create
214	64	epoll_ctl_old
215	64	epoll_wait_old
216	common	remap_file_pages	__x64_sys_remap_file_pages
217	common	getdents64		__x64_sys_getdents64
218	common	set_tid_address		__x64_sys_set_tid_address
219	common	restart_syscall		__x64_sys_restart_syscall
220	common	semtimedop		__x64_sys_semtimedop
221	common	fadvise64		__x64_sys_fadvise64
222	64	timer_create		__x64_sys_timer_create
223	common	timer_settime		__x64_sys_timer_settime
224	common	timer_gettime		__x64_sys_timer_gettime
225	common	timer_getoverrun	__x64_sys_timer_getoverrun
226	common	timer_delete		__x64_sys_timer_delete
227	common	clock_settime		__x64_sys_clock_settime
228	common	clock_gettime		__x64_sys_clock_gettime
229	common	clock_getres		__x64_sys_clock_getres
230	common	clock_nanosleep		__x64_sys_clock_nanosleep
231	common	exit_group		__x64_sys_exit_group
232	common	epoll_wait		__x64_sys_epoll_wait
233	common	epoll_ctl		__x64_sys_epoll_ctl
234	common	tgkill			__x64_sys_tgkill
235	common	utimes			__x64_sys_utimes
236	64	vserver
237	common	mbind			__x64_sys_mbind
238	common	set_mempolicy		__x64_sys_set_mempolicy
239	common	get_mempolicy		__x64_sys_get_mempolicy
240	common	mq_open			__x64_sys_mq_open
241	common	mq_unlink		__x64_sys_mq_unlink
242	common	mq_timedsend		__x64_sys_mq_timedsend
243	common	mq_timedreceive		__x64_sys_mq_timedreceive
244	64	mq_notify		__x64_sys_mq_notify
245	common	mq_getsetattr		__x64_sys_mq_getsetattr
246	64	kexec_load		__x64_sys_kexec_load
247	64	waitid			__x64_sys_waitid
248	common	add_key			__x64_sys_add_key
249	common	request_key		__x64_sys_request_key
250	common	keyctl			__x64_sys_keyctl
251	common	ioprio_set		__x64_sys_ioprio_set
252	common	ioprio_get		__x64_sys_ioprio_get
253	common	inotify_init		__x64_sys_inotify_init
254	common	inotify_add_watch	__x64_sys_inotify_add_watch
255	common	inotify_rm_watch	__x64_sys_inotify_rm_watch
256	common	migrate_pages		__x64_sys_migrate_pages
257	common	openat			__x64_sys_openat
258	common	mkdirat			__x64_sys_mkdirat
259	common	mknodat			__x64_sys_mknodat
260	common	fchownat		__x64_sys_fchownat
261	common	futimesat		__x64_sys_futimesat
262	common	newfstatat		__x64_sys_newfstatat
263	common	unlinkat		__x64_sys_unlinkat
264	common	renameat		__x64_sys_renameat
265	common	linkat			__x64_sys_linkat
266	common	symlinkat		__x64_sys_symlinkat
267	common	readlinkat		__x64_sys_readlinkat
268	common	fchmodat		__x64_sys_fchmodat
269	common	faccessat		__x64_sys_faccessat
270	common	pselect6		__x64_sys_pselect6
271	common	ppoll			__x64_sys_ppoll
272	common	unshare			__x64_sys_unshare
273	64	set_robust_list		__x64_sys_set_robust_list
274	64	get_robust_list		__x64_sys_get_robust_list
275	common	splice			__x64_sys_splice
276	common	tee			__x64_sys_tee
277	common	sync_file_range		__x64_sys_sync_file_range
278	64	vmsplice		__x64_sys_vmsplice
279	64	move_pages		__x64_sys_move_pages
280	common	utimensat		__x64_sys_utimensat
281	common	epoll_pwait		__x64_sys_epoll_pwait
282	common	signalfd		__x64_sys_signalfd
283	common	timerfd_create		__x64_sys_timerfd_create
284	common	eventfd			__x64_sys_eventfd
285	common	fallocate		__x64_sys_fallocate
286	common	timerfd_settime		__x64_sys_timerfd_settime
287	common	timerfd_gettime		__x64_sys_timerfd_gettime
288	common	accept4			__x64_sys_accept4
289	common	signalfd4		__x64_sys_signalfd4
290	common	eventfd2		__x64_sys_eventfd2
291	common	epoll_create1		__x64_sys_epoll_create1
292	common	dup3			__x64_sys_dup3
293	common	pipe2			__x64_sys_pipe2
294	common	inotify_init1		__x64_sys_inotify_init1
295	64	preadv			__x64_sys_preadv
296	64	pwritev			__x64_sys_pwritev
297	64	rt_tgsigqueueinfo	__x64_sys_rt_tgsigqueueinfo
298	common	perf_event_open		__x64_sys_perf_event_open
299	64	recvmmsg		__x64_sys_recvmmsg
300	common	fanotify_init		__x64_sys_fanotify_init
301	common	fanotify_mark		__x64_sys_fanotify_mark
302	common	prlimit64		__x64_sys_prlimit64
303	common	name_to_handle_at	__x64_sys_name_to_handle_at
304	common	open_by_handle_at	__x64_sys_open_by_handle_at
305	common	clock_adjtime		__x64_sys_clock_adjtime
306	common	syncfs			__x64_sys_syncfs
307	64	sendmmsg		__x64_sys_sendmmsg
308	common	setns			__x64_sys_setns
309	common	getcpu			__x64_sys_getcpu
310	64	process_vm_readv	__x64_sys_process_vm_readv
311	64	process_vm_writev	__x64_sys_process_vm_writev
312	common	kcmp			__x64_sys_kcmp
313	common	finit_module		__x64_sys_finit_module
314	common	sched_setattr		__x64_sys_sched_setattr
315	common	sched_getattr		__x64_sys_sched_getattr
316	common	renameat2		__x64_sys_renameat2
317	common	seccomp			__x64_sys_seccomp
318	common	getrandom		__x64_sys_getrandom
319	common	memfd_create		__x64_sys_memfd_create
320	common	kexec_file_load		__x64_sys_kexec_file_load
321	common	bpf			__x64_sys_bpf
322	64	execveat		__x64_sys_execveat/ptregs
323	common	userfaultfd		__x64_sys_userfaultfd
324	common	membarrier		__x64_sys_membarrier
325	common	mlock2			__x64_sys_mlock2
326	common	copy_file_range		__x64_sys_copy_file_range
327	64	preadv2			__x64_sys_preadv2
328	64	pwritev2		__x64_sys_pwritev2
329	common	pkey_mprotect		__x64_sys_pkey_mprotect
330	common	pkey_alloc		__x64_sys_pkey_alloc
331	common	pkey_free		__x64_sys_pkey_free
332	common	statx			__x64_sys_statx
333	common	io_pgetevents		__x64_sys_io_pgetevents
334	common	rseq			__x64_sys_rseq
# don't use numbers 387 through 423, add new calls after the last
# 'common' entry
424	common	pidfd_send_signal	__x64_sys_pidfd_send_signal
425	common	io_uring_setup		__x64_sys_io_uring_setup
426	common	io_uring_enter		__x64_sys_io_uring_enter
427	common	io_uring_register	__x64_sys_io_uring_register
428	common	open_tree		__x64_sys_open_tree
429	common	move_mount		__x64_sys_move_mount
430	common	fsopen			__x64_sys_fsopen
431	common	fsconfig		__x64_sys_fsconfig
432	common	fsmount			__x64_sys_fsmount
433	common	fspick			__x64_sys_fspick
434	common	pidfd_open		__x64_sys_pidfd_open
435	common	clone3			__x64_sys_clone3/ptregs

#
# x32-specific system call numbers start at 512 to avoid cache impact
# for native 64-bit operation. The __x32_compat_sys stubs are created
# on-the-fly for compat_sys_*() compatibility system calls if X86_X32
# is defined.
#
512	x32	rt_sigaction		__x32_compat_sys_rt_sigaction
513	x32	rt_sigreturn		sys32_x32_rt_sigreturn
514	x32	ioctl			__x32_compat_sys_ioctl
515	x32	readv			__x32_compat_sys_readv
516	x32	writev			__x32_compat_sys_writev
517	x32	recvfrom		__x32_compat_sys_recvfrom
518	x32	sendmsg			__x32_compat_sys_sendmsg
519	x32	recvmsg			__x32_compat_sys_recvmsg
520	x32	execve			__x32_compat_sys_execve/ptregs
521	x32	ptrace			__x32_compat_sys_ptrace
522	x32	rt_sigpending		__x32_compat_sys_rt_sigpending
523	x32	rt_sigtimedwait		__x32_compat_sys_rt_sigtimedwait_time64
524	x32	rt_sigqueueinfo		__x32_compat_sys_rt_sigqueueinfo
525	x32	sigaltstack		__x32_compat_sys_sigaltstack
526	x32	timer_create		__x32_compat_sys_timer_create
527	x32	mq_notify		__x32_compat_sys_mq_notify
528	x32	kexec_load		__x32_compat_sys_kexec_load
529	x32	waitid			__x32_compat_sys_waitid
530	x32	set_robust_list		__x32_compat_sys_set_robust_list
531	x32	get_robust_list		__x32_compat_sys_get_robust_list
532	x32	vmsplice		__x32_compat_sys_vmsplice
533	x32	move_pages		__x32_compat_sys_move_pages
534	x32	preadv			__x32_compat_sys_preadv64
535	x32	pwritev			__x32_compat_sys_pwritev64
536	x32	rt_tgsigqueueinfo	__x32_compat_sys_rt_tgsigqueueinfo
537	x32	recvmmsg		__x32_compat_sys_recvmmsg_time64
538	x32	sendmmsg		__x32_compat_sys_sendmmsg
539	x32	process_vm_readv	__x32_compat_sys_process_vm_readv
540	x32	process_vm_writev	__x32_compat_sys_process_vm_writev
541	x32	setsockopt		__x32_compat_sys_setsockopt
542	x32	getsockopt		__x32_compat_sys_getsockopt
543	x32	io_setup		__x32_compat_sys_io_setup
544	x32	io_submit		__x32_compat_sys_io_submit
545	x32	execveat		__x32_compat_sys_execveat/ptregs
546	x32	preadv2			__x32_compat_sys_preadv64v2
547	x32	pwritev2		__x32_compat_sys_pwritev64v2
	}
}

if {![info exists ::seccomp_bpf::_platform_data(i386)]} {
	set ::seccomp_bpf::_platform_data(i386) {
#
# 32-bit system call numbers and entry vectors
#
# The format is:
# <number> <abi> <name> <entry point> <compat entry point>
#
# The __ia32_sys and __ia32_compat_sys stubs are created on-the-fly for
# sys_*() system calls and compat_sys_*() compat system calls if
# IA32_EMULATION is defined, and expect struct pt_regs *regs as their only
# parameter.
#
# The abi is always "i386" for this file.
#
0	i386	restart_syscall		sys_restart_syscall		__ia32_sys_restart_syscall
1	i386	exit			sys_exit			__ia32_sys_exit
2	i386	fork			sys_fork			__ia32_sys_fork
3	i386	read			sys_read			__ia32_sys_read
4	i386	write			sys_write			__ia32_sys_write
5	i386	open			sys_open			__ia32_compat_sys_open
6	i386	close			sys_close			__ia32_sys_close
7	i386	waitpid			sys_waitpid			__ia32_sys_waitpid
8	i386	creat			sys_creat			__ia32_sys_creat
9	i386	link			sys_link			__ia32_sys_link
10	i386	unlink			sys_unlink			__ia32_sys_unlink
11	i386	execve			sys_execve			__ia32_compat_sys_execve
12	i386	chdir			sys_chdir			__ia32_sys_chdir
13	i386	time			sys_time32			__ia32_sys_time32
14	i386	mknod			sys_mknod			__ia32_sys_mknod
15	i386	chmod			sys_chmod			__ia32_sys_chmod
16	i386	lchown			sys_lchown16			__ia32_sys_lchown16
17	i386	break
18	i386	oldstat			sys_stat			__ia32_sys_stat
19	i386	lseek			sys_lseek			__ia32_compat_sys_lseek
20	i386	getpid			sys_getpid			__ia32_sys_getpid
21	i386	mount			sys_mount			__ia32_compat_sys_mount
22	i386	umount			sys_oldumount			__ia32_sys_oldumount
23	i386	setuid			sys_setuid16			__ia32_sys_setuid16
24	i386	getuid			sys_getuid16			__ia32_sys_getuid16
25	i386	stime			sys_stime32			__ia32_sys_stime32
26	i386	ptrace			sys_ptrace			__ia32_compat_sys_ptrace
27	i386	alarm			sys_alarm			__ia32_sys_alarm
28	i386	oldfstat		sys_fstat			__ia32_sys_fstat
29	i386	pause			sys_pause			__ia32_sys_pause
30	i386	utime			sys_utime32			__ia32_sys_utime32
31	i386	stty
32	i386	gtty
33	i386	access			sys_access			__ia32_sys_access
34	i386	nice			sys_nice			__ia32_sys_nice
35	i386	ftime
36	i386	sync			sys_sync			__ia32_sys_sync
37	i386	kill			sys_kill			__ia32_sys_kill
38	i386	rename			sys_rename			__ia32_sys_rename
39	i386	mkdir			sys_mkdir			__ia32_sys_mkdir
40	i386	rmdir			sys_rmdir			__ia32_sys_rmdir
41	i386	dup			sys_dup				__ia32_sys_dup
42	i386	pipe			sys_pipe			__ia32_sys_pipe
43	i386	times			sys_times			__ia32_compat_sys_times
44	i386	prof
45	i386	brk			sys_brk				__ia32_sys_brk
46	i386	setgid			sys_setgid16			__ia32_sys_setgid16
47	i386	getgid			sys_getgid16			__ia32_sys_getgid16
48	i386	signal			sys_signal			__ia32_sys_signal
49	i386	geteuid			sys_geteuid16			__ia32_sys_geteuid16
50	i386	getegid			sys_getegid16			__ia32_sys_getegid16
51	i386	acct			sys_acct			__ia32_sys_acct
52	i386	umount2			sys_umount			__ia32_sys_umount
53	i386	lock
54	i386	ioctl			sys_ioctl			__ia32_compat_sys_ioctl
55	i386	fcntl			sys_fcntl			__ia32_compat_sys_fcntl64
56	i386	mpx
57	i386	setpgid			sys_setpgid			__ia32_sys_setpgid
58	i386	ulimit
59	i386	oldolduname		sys_olduname			__ia32_sys_olduname
60	i386	umask			sys_umask			__ia32_sys_umask
61	i386	chroot			sys_chroot			__ia32_sys_chroot
62	i386	ustat			sys_ustat			__ia32_compat_sys_ustat
63	i386	dup2			sys_dup2			__ia32_sys_dup2
64	i386	getppid			sys_getppid			__ia32_sys_getppid
65	i386	getpgrp			sys_getpgrp			__ia32_sys_getpgrp
66	i386	setsid			sys_setsid			__ia32_sys_setsid
67	i386	sigaction		sys_sigaction			__ia32_compat_sys_sigaction
68	i386	sgetmask		sys_sgetmask			__ia32_sys_sgetmask
69	i386	ssetmask		sys_ssetmask			__ia32_sys_ssetmask
70	i386	setreuid		sys_setreuid16			__ia32_sys_setreuid16
71	i386	setregid		sys_setregid16			__ia32_sys_setregid16
72	i386	sigsuspend		sys_sigsuspend			__ia32_sys_sigsuspend
73	i386	sigpending		sys_sigpending			__ia32_compat_sys_sigpending
74	i386	sethostname		sys_sethostname			__ia32_sys_sethostname
75	i386	setrlimit		sys_setrlimit			__ia32_compat_sys_setrlimit
76	i386	getrlimit		sys_old_getrlimit		__ia32_compat_sys_old_getrlimit
77	i386	getrusage		sys_getrusage			__ia32_compat_sys_getrusage
78	i386	gettimeofday		sys_gettimeofday		__ia32_compat_sys_gettimeofday
79	i386	settimeofday		sys_settimeofday		__ia32_compat_sys_settimeofday
80	i386	getgroups		sys_getgroups16			__ia32_sys_getgroups16
81	i386	setgroups		sys_setgroups16			__ia32_sys_setgroups16
82	i386	select			sys_old_select			__ia32_compat_sys_old_select
83	i386	symlink			sys_symlink			__ia32_sys_symlink
84	i386	oldlstat		sys_lstat			__ia32_sys_lstat
85	i386	readlink		sys_readlink			__ia32_sys_readlink
86	i386	uselib			sys_uselib			__ia32_sys_uselib
87	i386	swapon			sys_swapon			__ia32_sys_swapon
88	i386	reboot			sys_reboot			__ia32_sys_reboot
89	i386	readdir			sys_old_readdir			__ia32_compat_sys_old_readdir
90	i386	mmap			sys_old_mmap			__ia32_compat_sys_x86_mmap
91	i386	munmap			sys_munmap			__ia32_sys_munmap
92	i386	truncate		sys_truncate			__ia32_compat_sys_truncate
93	i386	ftruncate		sys_ftruncate			__ia32_compat_sys_ftruncate
94	i386	fchmod			sys_fchmod			__ia32_sys_fchmod
95	i386	fchown			sys_fchown16			__ia32_sys_fchown16
96	i386	getpriority		sys_getpriority			__ia32_sys_getpriority
97	i386	setpriority		sys_setpriority			__ia32_sys_setpriority
98	i386	profil
99	i386	statfs			sys_statfs			__ia32_compat_sys_statfs
100	i386	fstatfs			sys_fstatfs			__ia32_compat_sys_fstatfs
101	i386	ioperm			sys_ioperm			__ia32_sys_ioperm
102	i386	socketcall		sys_socketcall			__ia32_compat_sys_socketcall
103	i386	syslog			sys_syslog			__ia32_sys_syslog
104	i386	setitimer		sys_setitimer			__ia32_compat_sys_setitimer
105	i386	getitimer		sys_getitimer			__ia32_compat_sys_getitimer
106	i386	stat			sys_newstat			__ia32_compat_sys_newstat
107	i386	lstat			sys_newlstat			__ia32_compat_sys_newlstat
108	i386	fstat			sys_newfstat			__ia32_compat_sys_newfstat
109	i386	olduname		sys_uname			__ia32_sys_uname
110	i386	iopl			sys_iopl			__ia32_sys_iopl
111	i386	vhangup			sys_vhangup			__ia32_sys_vhangup
112	i386	idle
113	i386	vm86old			sys_vm86old			__ia32_sys_ni_syscall
114	i386	wait4			sys_wait4			__ia32_compat_sys_wait4
115	i386	swapoff			sys_swapoff			__ia32_sys_swapoff
116	i386	sysinfo			sys_sysinfo			__ia32_compat_sys_sysinfo
117	i386	ipc			sys_ipc				__ia32_compat_sys_ipc
118	i386	fsync			sys_fsync			__ia32_sys_fsync
119	i386	sigreturn		sys_sigreturn			__ia32_compat_sys_sigreturn
120	i386	clone			sys_clone			__ia32_compat_sys_x86_clone
121	i386	setdomainname		sys_setdomainname		__ia32_sys_setdomainname
122	i386	uname			sys_newuname			__ia32_sys_newuname
123	i386	modify_ldt		sys_modify_ldt			__ia32_sys_modify_ldt
124	i386	adjtimex		sys_adjtimex_time32			__ia32_sys_adjtimex_time32
125	i386	mprotect		sys_mprotect			__ia32_sys_mprotect
126	i386	sigprocmask		sys_sigprocmask			__ia32_compat_sys_sigprocmask
127	i386	create_module
128	i386	init_module		sys_init_module			__ia32_sys_init_module
129	i386	delete_module		sys_delete_module		__ia32_sys_delete_module
130	i386	get_kernel_syms
131	i386	quotactl		sys_quotactl			__ia32_compat_sys_quotactl32
132	i386	getpgid			sys_getpgid			__ia32_sys_getpgid
133	i386	fchdir			sys_fchdir			__ia32_sys_fchdir
134	i386	bdflush			sys_bdflush			__ia32_sys_bdflush
135	i386	sysfs			sys_sysfs			__ia32_sys_sysfs
136	i386	personality		sys_personality			__ia32_sys_personality
137	i386	afs_syscall
138	i386	setfsuid		sys_setfsuid16			__ia32_sys_setfsuid16
139	i386	setfsgid		sys_setfsgid16			__ia32_sys_setfsgid16
140	i386	_llseek			sys_llseek			__ia32_sys_llseek
141	i386	getdents		sys_getdents			__ia32_compat_sys_getdents
142	i386	_newselect		sys_select			__ia32_compat_sys_select
143	i386	flock			sys_flock			__ia32_sys_flock
144	i386	msync			sys_msync			__ia32_sys_msync
145	i386	readv			sys_readv			__ia32_compat_sys_readv
146	i386	writev			sys_writev			__ia32_compat_sys_writev
147	i386	getsid			sys_getsid			__ia32_sys_getsid
148	i386	fdatasync		sys_fdatasync			__ia32_sys_fdatasync
149	i386	_sysctl			sys_sysctl			__ia32_compat_sys_sysctl
150	i386	mlock			sys_mlock			__ia32_sys_mlock
151	i386	munlock			sys_munlock			__ia32_sys_munlock
152	i386	mlockall		sys_mlockall			__ia32_sys_mlockall
153	i386	munlockall		sys_munlockall			__ia32_sys_munlockall
154	i386	sched_setparam		sys_sched_setparam		__ia32_sys_sched_setparam
155	i386	sched_getparam		sys_sched_getparam		__ia32_sys_sched_getparam
156	i386	sched_setscheduler	sys_sched_setscheduler		__ia32_sys_sched_setscheduler
157	i386	sched_getscheduler	sys_sched_getscheduler		__ia32_sys_sched_getscheduler
158	i386	sched_yield		sys_sched_yield			__ia32_sys_sched_yield
159	i386	sched_get_priority_max	sys_sched_get_priority_max	__ia32_sys_sched_get_priority_max
160	i386	sched_get_priority_min	sys_sched_get_priority_min	__ia32_sys_sched_get_priority_min
161	i386	sched_rr_get_interval	sys_sched_rr_get_interval_time32	__ia32_sys_sched_rr_get_interval_time32
162	i386	nanosleep		sys_nanosleep_time32		__ia32_sys_nanosleep_time32
163	i386	mremap			sys_mremap			__ia32_sys_mremap
164	i386	setresuid		sys_setresuid16			__ia32_sys_setresuid16
165	i386	getresuid		sys_getresuid16			__ia32_sys_getresuid16
166	i386	vm86			sys_vm86			__ia32_sys_ni_syscall
167	i386	query_module
168	i386	poll			sys_poll			__ia32_sys_poll
169	i386	nfsservctl
170	i386	setresgid		sys_setresgid16			__ia32_sys_setresgid16
171	i386	getresgid		sys_getresgid16			__ia32_sys_getresgid16
172	i386	prctl			sys_prctl			__ia32_sys_prctl
173	i386	rt_sigreturn		sys_rt_sigreturn		__ia32_compat_sys_rt_sigreturn
174	i386	rt_sigaction		sys_rt_sigaction		__ia32_compat_sys_rt_sigaction
175	i386	rt_sigprocmask		sys_rt_sigprocmask		__ia32_compat_sys_rt_sigprocmask
176	i386	rt_sigpending		sys_rt_sigpending		__ia32_compat_sys_rt_sigpending
177	i386	rt_sigtimedwait		sys_rt_sigtimedwait_time32	__ia32_compat_sys_rt_sigtimedwait_time32
178	i386	rt_sigqueueinfo		sys_rt_sigqueueinfo		__ia32_compat_sys_rt_sigqueueinfo
179	i386	rt_sigsuspend		sys_rt_sigsuspend		__ia32_compat_sys_rt_sigsuspend
180	i386	pread64			sys_pread64			__ia32_compat_sys_x86_pread
181	i386	pwrite64		sys_pwrite64			__ia32_compat_sys_x86_pwrite
182	i386	chown			sys_chown16			__ia32_sys_chown16
183	i386	getcwd			sys_getcwd			__ia32_sys_getcwd
184	i386	capget			sys_capget			__ia32_sys_capget
185	i386	capset			sys_capset			__ia32_sys_capset
186	i386	sigaltstack		sys_sigaltstack			__ia32_compat_sys_sigaltstack
187	i386	sendfile		sys_sendfile			__ia32_compat_sys_sendfile
188	i386	getpmsg
189	i386	putpmsg
190	i386	vfork			sys_vfork			__ia32_sys_vfork
191	i386	ugetrlimit		sys_getrlimit			__ia32_compat_sys_getrlimit
192	i386	mmap2			sys_mmap_pgoff			__ia32_sys_mmap_pgoff
193	i386	truncate64		sys_truncate64			__ia32_compat_sys_x86_truncate64
194	i386	ftruncate64		sys_ftruncate64			__ia32_compat_sys_x86_ftruncate64
195	i386	stat64			sys_stat64			__ia32_compat_sys_x86_stat64
196	i386	lstat64			sys_lstat64			__ia32_compat_sys_x86_lstat64
197	i386	fstat64			sys_fstat64			__ia32_compat_sys_x86_fstat64
198	i386	lchown32		sys_lchown			__ia32_sys_lchown
199	i386	getuid32		sys_getuid			__ia32_sys_getuid
200	i386	getgid32		sys_getgid			__ia32_sys_getgid
201	i386	geteuid32		sys_geteuid			__ia32_sys_geteuid
202	i386	getegid32		sys_getegid			__ia32_sys_getegid
203	i386	setreuid32		sys_setreuid			__ia32_sys_setreuid
204	i386	setregid32		sys_setregid			__ia32_sys_setregid
205	i386	getgroups32		sys_getgroups			__ia32_sys_getgroups
206	i386	setgroups32		sys_setgroups			__ia32_sys_setgroups
207	i386	fchown32		sys_fchown			__ia32_sys_fchown
208	i386	setresuid32		sys_setresuid			__ia32_sys_setresuid
209	i386	getresuid32		sys_getresuid			__ia32_sys_getresuid
210	i386	setresgid32		sys_setresgid			__ia32_sys_setresgid
211	i386	getresgid32		sys_getresgid			__ia32_sys_getresgid
212	i386	chown32			sys_chown			__ia32_sys_chown
213	i386	setuid32		sys_setuid			__ia32_sys_setuid
214	i386	setgid32		sys_setgid			__ia32_sys_setgid
215	i386	setfsuid32		sys_setfsuid			__ia32_sys_setfsuid
216	i386	setfsgid32		sys_setfsgid			__ia32_sys_setfsgid
217	i386	pivot_root		sys_pivot_root			__ia32_sys_pivot_root
218	i386	mincore			sys_mincore			__ia32_sys_mincore
219	i386	madvise			sys_madvise			__ia32_sys_madvise
220	i386	getdents64		sys_getdents64			__ia32_sys_getdents64
221	i386	fcntl64			sys_fcntl64			__ia32_compat_sys_fcntl64
# 222 is unused
# 223 is unused
224	i386	gettid			sys_gettid			__ia32_sys_gettid
225	i386	readahead		sys_readahead			__ia32_compat_sys_x86_readahead
226	i386	setxattr		sys_setxattr			__ia32_sys_setxattr
227	i386	lsetxattr		sys_lsetxattr			__ia32_sys_lsetxattr
228	i386	fsetxattr		sys_fsetxattr			__ia32_sys_fsetxattr
229	i386	getxattr		sys_getxattr			__ia32_sys_getxattr
230	i386	lgetxattr		sys_lgetxattr			__ia32_sys_lgetxattr
231	i386	fgetxattr		sys_fgetxattr			__ia32_sys_fgetxattr
232	i386	listxattr		sys_listxattr			__ia32_sys_listxattr
233	i386	llistxattr		sys_llistxattr			__ia32_sys_llistxattr
234	i386	flistxattr		sys_flistxattr			__ia32_sys_flistxattr
235	i386	removexattr		sys_removexattr			__ia32_sys_removexattr
236	i386	lremovexattr		sys_lremovexattr		__ia32_sys_lremovexattr
237	i386	fremovexattr		sys_fremovexattr		__ia32_sys_fremovexattr
238	i386	tkill			sys_tkill			__ia32_sys_tkill
239	i386	sendfile64		sys_sendfile64			__ia32_sys_sendfile64
240	i386	futex			sys_futex_time32		__ia32_sys_futex_time32
241	i386	sched_setaffinity	sys_sched_setaffinity		__ia32_compat_sys_sched_setaffinity
242	i386	sched_getaffinity	sys_sched_getaffinity		__ia32_compat_sys_sched_getaffinity
243	i386	set_thread_area		sys_set_thread_area		__ia32_sys_set_thread_area
244	i386	get_thread_area		sys_get_thread_area		__ia32_sys_get_thread_area
245	i386	io_setup		sys_io_setup			__ia32_compat_sys_io_setup
246	i386	io_destroy		sys_io_destroy			__ia32_sys_io_destroy
247	i386	io_getevents		sys_io_getevents_time32		__ia32_sys_io_getevents_time32
248	i386	io_submit		sys_io_submit			__ia32_compat_sys_io_submit
249	i386	io_cancel		sys_io_cancel			__ia32_sys_io_cancel
250	i386	fadvise64		sys_fadvise64			__ia32_compat_sys_x86_fadvise64
# 251 is available for reuse (was briefly sys_set_zone_reclaim)
252	i386	exit_group		sys_exit_group			__ia32_sys_exit_group
253	i386	lookup_dcookie		sys_lookup_dcookie		__ia32_compat_sys_lookup_dcookie
254	i386	epoll_create		sys_epoll_create		__ia32_sys_epoll_create
255	i386	epoll_ctl		sys_epoll_ctl			__ia32_sys_epoll_ctl
256	i386	epoll_wait		sys_epoll_wait			__ia32_sys_epoll_wait
257	i386	remap_file_pages	sys_remap_file_pages		__ia32_sys_remap_file_pages
258	i386	set_tid_address		sys_set_tid_address		__ia32_sys_set_tid_address
259	i386	timer_create		sys_timer_create		__ia32_compat_sys_timer_create
260	i386	timer_settime		sys_timer_settime32		__ia32_sys_timer_settime32
261	i386	timer_gettime		sys_timer_gettime32		__ia32_sys_timer_gettime32
262	i386	timer_getoverrun	sys_timer_getoverrun		__ia32_sys_timer_getoverrun
263	i386	timer_delete		sys_timer_delete		__ia32_sys_timer_delete
264	i386	clock_settime		sys_clock_settime32		__ia32_sys_clock_settime32
265	i386	clock_gettime		sys_clock_gettime32		__ia32_sys_clock_gettime32
266	i386	clock_getres		sys_clock_getres_time32		__ia32_sys_clock_getres_time32
267	i386	clock_nanosleep		sys_clock_nanosleep_time32	__ia32_sys_clock_nanosleep_time32
268	i386	statfs64		sys_statfs64			__ia32_compat_sys_statfs64
269	i386	fstatfs64		sys_fstatfs64			__ia32_compat_sys_fstatfs64
270	i386	tgkill			sys_tgkill			__ia32_sys_tgkill
271	i386	utimes			sys_utimes_time32		__ia32_sys_utimes_time32
272	i386	fadvise64_64		sys_fadvise64_64		__ia32_compat_sys_x86_fadvise64_64
273	i386	vserver
274	i386	mbind			sys_mbind			__ia32_sys_mbind
275	i386	get_mempolicy		sys_get_mempolicy		__ia32_compat_sys_get_mempolicy
276	i386	set_mempolicy		sys_set_mempolicy		__ia32_sys_set_mempolicy
277	i386	mq_open			sys_mq_open			__ia32_compat_sys_mq_open
278	i386	mq_unlink		sys_mq_unlink			__ia32_sys_mq_unlink
279	i386	mq_timedsend		sys_mq_timedsend_time32		__ia32_sys_mq_timedsend_time32
280	i386	mq_timedreceive		sys_mq_timedreceive_time32	__ia32_sys_mq_timedreceive_time32
281	i386	mq_notify		sys_mq_notify			__ia32_compat_sys_mq_notify
282	i386	mq_getsetattr		sys_mq_getsetattr		__ia32_compat_sys_mq_getsetattr
283	i386	kexec_load		sys_kexec_load			__ia32_compat_sys_kexec_load
284	i386	waitid			sys_waitid			__ia32_compat_sys_waitid
# 285 sys_setaltroot
286	i386	add_key			sys_add_key			__ia32_sys_add_key
287	i386	request_key		sys_request_key			__ia32_sys_request_key
288	i386	keyctl			sys_keyctl			__ia32_compat_sys_keyctl
289	i386	ioprio_set		sys_ioprio_set			__ia32_sys_ioprio_set
290	i386	ioprio_get		sys_ioprio_get			__ia32_sys_ioprio_get
291	i386	inotify_init		sys_inotify_init		__ia32_sys_inotify_init
292	i386	inotify_add_watch	sys_inotify_add_watch		__ia32_sys_inotify_add_watch
293	i386	inotify_rm_watch	sys_inotify_rm_watch		__ia32_sys_inotify_rm_watch
294	i386	migrate_pages		sys_migrate_pages		__ia32_sys_migrate_pages
295	i386	openat			sys_openat			__ia32_compat_sys_openat
296	i386	mkdirat			sys_mkdirat			__ia32_sys_mkdirat
297	i386	mknodat			sys_mknodat			__ia32_sys_mknodat
298	i386	fchownat		sys_fchownat			__ia32_sys_fchownat
299	i386	futimesat		sys_futimesat_time32		__ia32_sys_futimesat_time32
300	i386	fstatat64		sys_fstatat64			__ia32_compat_sys_x86_fstatat
301	i386	unlinkat		sys_unlinkat			__ia32_sys_unlinkat
302	i386	renameat		sys_renameat			__ia32_sys_renameat
303	i386	linkat			sys_linkat			__ia32_sys_linkat
304	i386	symlinkat		sys_symlinkat			__ia32_sys_symlinkat
305	i386	readlinkat		sys_readlinkat			__ia32_sys_readlinkat
306	i386	fchmodat		sys_fchmodat			__ia32_sys_fchmodat
307	i386	faccessat		sys_faccessat			__ia32_sys_faccessat
308	i386	pselect6		sys_pselect6_time32		__ia32_compat_sys_pselect6_time32
309	i386	ppoll			sys_ppoll_time32		__ia32_compat_sys_ppoll_time32
310	i386	unshare			sys_unshare			__ia32_sys_unshare
311	i386	set_robust_list		sys_set_robust_list		__ia32_compat_sys_set_robust_list
312	i386	get_robust_list		sys_get_robust_list		__ia32_compat_sys_get_robust_list
313	i386	splice			sys_splice			__ia32_sys_splice
314	i386	sync_file_range		sys_sync_file_range		__ia32_compat_sys_x86_sync_file_range
315	i386	tee			sys_tee				__ia32_sys_tee
316	i386	vmsplice		sys_vmsplice			__ia32_compat_sys_vmsplice
317	i386	move_pages		sys_move_pages			__ia32_compat_sys_move_pages
318	i386	getcpu			sys_getcpu			__ia32_sys_getcpu
319	i386	epoll_pwait		sys_epoll_pwait			__ia32_sys_epoll_pwait
320	i386	utimensat		sys_utimensat_time32		__ia32_sys_utimensat_time32
321	i386	signalfd		sys_signalfd			__ia32_compat_sys_signalfd
322	i386	timerfd_create		sys_timerfd_create		__ia32_sys_timerfd_create
323	i386	eventfd			sys_eventfd			__ia32_sys_eventfd
324	i386	fallocate		sys_fallocate			__ia32_compat_sys_x86_fallocate
325	i386	timerfd_settime		sys_timerfd_settime32		__ia32_sys_timerfd_settime32
326	i386	timerfd_gettime		sys_timerfd_gettime32		__ia32_sys_timerfd_gettime32
327	i386	signalfd4		sys_signalfd4			__ia32_compat_sys_signalfd4
328	i386	eventfd2		sys_eventfd2			__ia32_sys_eventfd2
329	i386	epoll_create1		sys_epoll_create1		__ia32_sys_epoll_create1
330	i386	dup3			sys_dup3			__ia32_sys_dup3
331	i386	pipe2			sys_pipe2			__ia32_sys_pipe2
332	i386	inotify_init1		sys_inotify_init1		__ia32_sys_inotify_init1
333	i386	preadv			sys_preadv			__ia32_compat_sys_preadv
334	i386	pwritev			sys_pwritev			__ia32_compat_sys_pwritev
335	i386	rt_tgsigqueueinfo	sys_rt_tgsigqueueinfo		__ia32_compat_sys_rt_tgsigqueueinfo
336	i386	perf_event_open		sys_perf_event_open		__ia32_sys_perf_event_open
337	i386	recvmmsg		sys_recvmmsg_time32		__ia32_compat_sys_recvmmsg_time32
338	i386	fanotify_init		sys_fanotify_init		__ia32_sys_fanotify_init
339	i386	fanotify_mark		sys_fanotify_mark		__ia32_compat_sys_fanotify_mark
340	i386	prlimit64		sys_prlimit64			__ia32_sys_prlimit64
341	i386	name_to_handle_at	sys_name_to_handle_at		__ia32_sys_name_to_handle_at
342	i386	open_by_handle_at	sys_open_by_handle_at		__ia32_compat_sys_open_by_handle_at
343	i386	clock_adjtime		sys_clock_adjtime32		__ia32_sys_clock_adjtime32
344	i386	syncfs			sys_syncfs			__ia32_sys_syncfs
345	i386	sendmmsg		sys_sendmmsg			__ia32_compat_sys_sendmmsg
346	i386	setns			sys_setns			__ia32_sys_setns
347	i386	process_vm_readv	sys_process_vm_readv		__ia32_compat_sys_process_vm_readv
348	i386	process_vm_writev	sys_process_vm_writev		__ia32_compat_sys_process_vm_writev
349	i386	kcmp			sys_kcmp			__ia32_sys_kcmp
350	i386	finit_module		sys_finit_module		__ia32_sys_finit_module
351	i386	sched_setattr		sys_sched_setattr		__ia32_sys_sched_setattr
352	i386	sched_getattr		sys_sched_getattr		__ia32_sys_sched_getattr
353	i386	renameat2		sys_renameat2			__ia32_sys_renameat2
354	i386	seccomp			sys_seccomp			__ia32_sys_seccomp
355	i386	getrandom		sys_getrandom			__ia32_sys_getrandom
356	i386	memfd_create		sys_memfd_create		__ia32_sys_memfd_create
357	i386	bpf			sys_bpf				__ia32_sys_bpf
358	i386	execveat		sys_execveat			__ia32_compat_sys_execveat
359	i386	socket			sys_socket			__ia32_sys_socket
360	i386	socketpair		sys_socketpair			__ia32_sys_socketpair
361	i386	bind			sys_bind			__ia32_sys_bind
362	i386	connect			sys_connect			__ia32_sys_connect
363	i386	listen			sys_listen			__ia32_sys_listen
364	i386	accept4			sys_accept4			__ia32_sys_accept4
365	i386	getsockopt		sys_getsockopt			__ia32_compat_sys_getsockopt
366	i386	setsockopt		sys_setsockopt			__ia32_compat_sys_setsockopt
367	i386	getsockname		sys_getsockname			__ia32_sys_getsockname
368	i386	getpeername		sys_getpeername			__ia32_sys_getpeername
369	i386	sendto			sys_sendto			__ia32_sys_sendto
370	i386	sendmsg			sys_sendmsg			__ia32_compat_sys_sendmsg
371	i386	recvfrom		sys_recvfrom			__ia32_compat_sys_recvfrom
372	i386	recvmsg			sys_recvmsg			__ia32_compat_sys_recvmsg
373	i386	shutdown		sys_shutdown			__ia32_sys_shutdown
374	i386	userfaultfd		sys_userfaultfd			__ia32_sys_userfaultfd
375	i386	membarrier		sys_membarrier			__ia32_sys_membarrier
376	i386	mlock2			sys_mlock2			__ia32_sys_mlock2
377	i386	copy_file_range		sys_copy_file_range		__ia32_sys_copy_file_range
378	i386	preadv2			sys_preadv2			__ia32_compat_sys_preadv2
379	i386	pwritev2		sys_pwritev2			__ia32_compat_sys_pwritev2
380	i386	pkey_mprotect		sys_pkey_mprotect		__ia32_sys_pkey_mprotect
381	i386	pkey_alloc		sys_pkey_alloc			__ia32_sys_pkey_alloc
382	i386	pkey_free		sys_pkey_free			__ia32_sys_pkey_free
383	i386	statx			sys_statx			__ia32_sys_statx
384	i386	arch_prctl		sys_arch_prctl			__ia32_compat_sys_arch_prctl
385	i386	io_pgetevents		sys_io_pgetevents_time32	__ia32_compat_sys_io_pgetevents
386	i386	rseq			sys_rseq			__ia32_sys_rseq
393	i386	semget			sys_semget    			__ia32_sys_semget
394	i386	semctl			sys_semctl    			__ia32_compat_sys_semctl
395	i386	shmget			sys_shmget    			__ia32_sys_shmget
396	i386	shmctl			sys_shmctl    			__ia32_compat_sys_shmctl
397	i386	shmat			sys_shmat     			__ia32_compat_sys_shmat
398	i386	shmdt			sys_shmdt     			__ia32_sys_shmdt
399	i386	msgget			sys_msgget    			__ia32_sys_msgget
400	i386	msgsnd			sys_msgsnd    			__ia32_compat_sys_msgsnd
401	i386	msgrcv			sys_msgrcv    			__ia32_compat_sys_msgrcv
402	i386	msgctl			sys_msgctl    			__ia32_compat_sys_msgctl
403	i386	clock_gettime64		sys_clock_gettime		__ia32_sys_clock_gettime
404	i386	clock_settime64		sys_clock_settime		__ia32_sys_clock_settime
405	i386	clock_adjtime64		sys_clock_adjtime		__ia32_sys_clock_adjtime
406	i386	clock_getres_time64	sys_clock_getres		__ia32_sys_clock_getres
407	i386	clock_nanosleep_time64	sys_clock_nanosleep		__ia32_sys_clock_nanosleep
408	i386	timer_gettime64		sys_timer_gettime		__ia32_sys_timer_gettime
409	i386	timer_settime64		sys_timer_settime		__ia32_sys_timer_settime
410	i386	timerfd_gettime64	sys_timerfd_gettime		__ia32_sys_timerfd_gettime
411	i386	timerfd_settime64	sys_timerfd_settime		__ia32_sys_timerfd_settime
412	i386	utimensat_time64	sys_utimensat			__ia32_sys_utimensat
413	i386	pselect6_time64		sys_pselect6			__ia32_compat_sys_pselect6_time64
414	i386	ppoll_time64		sys_ppoll			__ia32_compat_sys_ppoll_time64
416	i386	io_pgetevents_time64	sys_io_pgetevents		__ia32_sys_io_pgetevents
417	i386	recvmmsg_time64		sys_recvmmsg			__ia32_compat_sys_recvmmsg_time64
418	i386	mq_timedsend_time64	sys_mq_timedsend		__ia32_sys_mq_timedsend
419	i386	mq_timedreceive_time64	sys_mq_timedreceive		__ia32_sys_mq_timedreceive
420	i386	semtimedop_time64	sys_semtimedop			__ia32_sys_semtimedop
421	i386	rt_sigtimedwait_time64	sys_rt_sigtimedwait		__ia32_compat_sys_rt_sigtimedwait_time64
422	i386	futex_time64		sys_futex			__ia32_sys_futex
423	i386	sched_rr_get_interval_time64	sys_sched_rr_get_interval	__ia32_sys_sched_rr_get_interval
424	i386	pidfd_send_signal	sys_pidfd_send_signal		__ia32_sys_pidfd_send_signal
425	i386	io_uring_setup		sys_io_uring_setup		__ia32_sys_io_uring_setup
426	i386	io_uring_enter		sys_io_uring_enter		__ia32_sys_io_uring_enter
427	i386	io_uring_register	sys_io_uring_register		__ia32_sys_io_uring_register
428	i386	open_tree		sys_open_tree			__ia32_sys_open_tree
429	i386	move_mount		sys_move_mount			__ia32_sys_move_mount
430	i386	fsopen			sys_fsopen			__ia32_sys_fsopen
431	i386	fsconfig		sys_fsconfig			__ia32_sys_fsconfig
432	i386	fsmount			sys_fsmount			__ia32_sys_fsmount
433	i386	fspick			sys_fspick			__ia32_sys_fspick
434	i386	pidfd_open		sys_pidfd_open			__ia32_sys_pidfd_open
435	i386	clone3			sys_clone3			__ia32_sys_clone3
	}
}

proc ::seccomp_bpf::_loadSystemCallTable {platform data} {
	if {[info exists ::seccomp_bpf::_systemCallTableLookup_${platform}_]} {
		return
	}

	foreach line [split $data "\n"] {
		set line [regsub {#.*$} $line ""]
		set line [string trim $line]
		if {$line eq ""} {
			continue
		}

		if {![string is list -strict $line]} {
			continue
		}

		set name [lindex $line 2]
		set id   [lindex $line 0]

		lappend "::seccomp_bpf::_systemCallTableLookup_${platform}_($name)" $id
		lappend "::seccomp_bpf::_systemCallReverseTableLookup_${platform}_($id)" $name
	}
}

proc ::seccomp_bpf::init_platform {handle platform {data ""}} {
	if {$data eq ""} {
		set data $::seccomp_bpf::_platform_data($platform)
	}
	
	::seccomp_bpf::_loadSystemCallTable $platform $data
	lappend ::seccomp_bpf::_platforms($handle) $platform
}

proc ::seccomp_bpf::uninit_platform {platform} {
	foreach handle [array names ::seccomp_bpf::_platforms] {
		foreach checkPlatform $::seccomp_bpf::_platforms($handle) {
			if {$checkPlatform eq $platform} {
				return false
			}
		}
	}

	unset -nocomplain ::seccomp_bpf::_systemCallTableLookup_${platform}_
	unset -nocomplain ::seccomp_bpf::_systemCallReverseTableLookup_${platform}_

	return true
}

proc ::seccomp_bpf::new {} {
	incr ::seccomp_bpf::_handle_index
	set handle "::seccomp_bpf::handle${::seccomp_bpf::_handle_index}"

	return $handle
}

proc ::seccomp_bpf::delete {handle} {
	unset ::seccomp_bpf::_platforms($handle)
	unset ::seccomp_bpf::_platform_code($handle)
	unset ::seccomp_bpf::_variables($handle)
}

proc ::seccomp_bpf::_is_host_variable {var} {
	switch -glob -- $var {
		{$nr} - {$arch} - {$args(*)} {
			return true
		}
	}

	return false
}

proc ::seccomp_bpf::_is_compiler_variable {var} {
	if {[_is_host_variable $var]} {
		return false
	}

	if {[string index $var 0] eq {$}} {
		return true
	}

	return false
}

proc ::seccomp_bpf::_get_compiler_variable {handle var {default ""}} {
	set varName [string range $var 1 end]

	set value $default
	catch {
		set value [dict get $::seccomp_bpf::_variables($handle) $varName]
	}

	return $value
}

proc ::seccomp_bpf::_load_var {var} {
	set output [list]

	switch -glob -- $var {
		{$nr} {
			lappend output "BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof(struct seccomp_data, nr))),"
		}
		{$arch} {
			lappend output "BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof(struct seccomp_data, arch))),"
		}
		{$args(*)} {
			set idx [lindex [split $var ()] 1]
			lappend output "BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof(struct seccomp_data, args\[$idx\]))),"
		}
		default {
			# Compare two immediate values
			lappend output "BPF_STMT(BPF_LD | BPF_W | BPF_IMM, $var),"
		}
	}

	return $output
}

proc ::seccomp_bpf::_invert_op_direction {op} {
	switch -exact -- $op {
		">" { set op "<" }
		"<" { set op ">" }
		">=" { set op "<=" }
		"<=" { set op ">=" }
	}

	return $op
}
proc ::seccomp_bpf::_parse_if {handle platform condition truelabel falselabel endlabel} {
	set a [lindex $condition 0]
	set b [lindex $condition 2]
	set op [lindex $condition 1]
	set postCompareOutput [list]
	set output [list]

	if {$a eq $b} {
		if {$op in {== eq}} {
			return [list "BPF_STMT(BPF_JMP, @@${truelabel}@@), /* if ($condition) always true */"]
		} elseif {$op in {!= ne}} {
			return [list "BPF_STMT(BPF_JMP, @@${falselabel}@@), /* if ($condition) always false */"]
		}
	}

	set compareAgainst "K"
	if {![_is_host_variable $a]} {
		if {[_is_host_variable $b]} {
			set x $a
			set a $b
			set b $a

			set op [_invert_op_direction $op]
		}
	}

	if {[_is_host_variable $b]} {
		lappend output {*}[::seccomp_bpf::_load_var $b]
		lappend output {BPF_STMT(BPF_ST, 0),}
		lappend output {BPF_STMT(BPF_LDX | BPF_W | BPF_MEM, 0),}
		set compareAgainst "X"
		set b 0
	} elseif {[_is_compiler_variable $b]} {
		set b [_get_compiler_variable $handle $b]
	}

	lappend output {*}[::seccomp_bpf::_load_var $a]

	switch -glob -- $a {
		{$nr} {
			set syscall_ids [list]
			foreach syscall $b {
				lappend syscall_ids {*}[set ::seccomp_bpf::_systemCallTableLookup_${platform}_($syscall)]
			}
			set b $syscall_ids

			if {[llength $b] > 1} {
				if {$op in {eq ==}} {
					set op "in"
				} elseif {$op in {ne !=}} {
					set op "ni"
				}
			}
		}
		{$arch} {
			set b "AUDIT_ARCH_[string toupper $b]"
		}
	}

	switch -exact $op {
		"==" - "eq" {
			lappend output "BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_${compareAgainst}, $b, @@${truelabel}@@, @@${falselabel}@@),"
		}
		"!=" - "ne" {
			lappend output "BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_${compareAgainst}, $b, @@${falselabel}@@, @@${truelabel}@@),"
		}
		"in" {
			foreach item $b {
				lappend output "BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_${compareAgainst}, $item, @@${truelabel}@@, 0),"
			}
			lappend output "BPF_STMT(BPF_JMP, @@${falselabel}@@),"
		}
		"ni" {
			foreach item $b {
				lappend output "BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_${compareAgainst}, $item, @@${falselabel}@@, 0),"
			}
			lappend output "BPF_STMT(BPF_JMP, @@${truelabel}@@),"
		}
		">" {
			lappend output "BPF_JUMP(BPF_JMP | BPF_JGT | BPF_${compareAgainst}, $b, @@${truelabel}@@, @@${falselabel}@@),"
		}
		">=" {
			lappend output "BPF_JUMP(BPF_JMP | BPF_JGE | BPF_${compareAgainst}, $b, @@${truelabel}@@, @@${falselabel}@@),"
		}
		"<" {
			lappend output "BPF_JUMP(BPF_JMP | BPF_JGE | BPF_${compareAgainst}, $b, @@${falselabel}@@, @@${truelabel}@@),"
		}
		"<=" {
			lappend output "BPF_JUMP(BPF_JMP | BPF_JGT | BPF_${compareAgainst}, $b, @@${falselabel}@@, @@${truelabel}@@),"
		}
		default {
			return -code error "unimplemented: $op"
		}
	}

	if {[llength $postCompareOutput] > 0} {
		lappend output {*}$postCompareOutput
	}

	if {[llength $output] == 0} {
		return [list]
	}

	set line0 [lindex $output 0]
	set line0 "$line0 /* if ($condition) ... */"
	set output [lreplace $output 0 0 $line0]

	return $output
}

proc ::seccomp_bpf::_fix_labels {code} {
	set line_number 0

	array set labels [list]

	# Eliminate pointless jumps
	for {set idx 0} {$idx < [llength $code]} {incr idx} {
		set line [lindex $code $idx]
		if {[string match "BPF_STMT(BPF_JMP, @@*@@),*" $line]} {
			regexp {^BPF_STMT\(BPF_JMP, (.*)\),.*$} $line -> jump_label

			set nextlines [list]
			for {set subidx [expr {$idx + 1}]} {$subidx < [llength $code]} {incr subidx} {
				set nextline [lindex $code $subidx]
				if {![string match "@@*@@" $nextline]} {
					break
				}
				lappend nextlines $nextline
			}

			if {$jump_label in $nextlines} {
				set code [lreplace $code $idx $idx]
				incr idx -1
				continue
			}
		}
	}

	foreach line $code {
		if {[string match "@@*@@" $line]} {
			set labels($line) $line_number
			continue
		}
		incr line_number
	}

	set output [list]
	foreach line $code {
		if {[string match "@@*@@" $line]} {
			continue
		}

		foreach {label jump_line_number} [array get labels] {
			incr jump_line_number -1

			# The kernel will forbid backwards jumps, so ensure we
			# do not emit them
			if {$jump_line_number < 0} {
				unset labels($label)
				continue
			}

			set labels($label) $jump_line_number
		}
		set line [string map [array get labels] $line]

		lappend output $line
	}

	return $output
}

proc ::seccomp_bpf::_eval {handle platform code {label ""}} {
	set output [list]

	if {$label ne ""} {
		lappend output "@@${label}@@"
	}

	if {$code eq ""} {
		return [list]
	}

	set if_idx -1
	for {set idx 0} {$idx < [llength $code]} {incr idx} {
		set word [lindex $code $idx]
		switch -exact -- $word {
			"if" {
				incr if_idx

				set condition [lindex $code [incr idx]]
				set code_true [lindex $code [incr idx]]
				set check_else [lindex $code [expr {$idx + 1}]]
				if {$check_else eq "else"} {
					incr idx
					set code_false [lindex $code [incr idx]]
				} else {
					set code_false ""
				}

				set label_end ${label}.if_end.${if_idx}
				set label_true ${label}.if_true.${if_idx}
				set label_false ${label}.if_false.${if_idx}

				if {$code_true eq ""} {
					set label_true $label_end
				}

				if {$code_false eq ""} {
					set label_false $label_end
				}

				if {$label_true != $label_end || $label_false != $label_end} {
					lappend output {*}[::seccomp_bpf::_parse_if $handle $platform $condition $label_true $label_false $label_end]
				}
				if {$code_true ne ""} {
					lappend output {*}[::seccomp_bpf::_eval $handle $platform $code_true $label_true]
				}
				if {$code_false ne ""} {
					lappend output {*}[::seccomp_bpf::_eval $handle $platform $code_false $label_false]
				}
				lappend output "@@${label}.if_end.${if_idx}@@"
			}
			"return" {
				set retcode [lindex $code [incr idx]]

				switch -exact $retcode {
					"allow" {
						lappend output {BPF_STMT(BPF_RET, SECCOMP_RET_ALLOW),}
					}
					"trap" {
						lappend output {BPF_STMT(BPF_RET, SECCOMP_RET_TRAP),}
					}
					"kill" {
						lappend output {BPF_STMT(BPF_RET, SECCOMP_RET_KILL),}
					}
					"errno" {
						set retcode_errno [lindex $code [incr idx]]
						lappend output "BPF_STMT(BPF_RET, SECCOMP_RET_ERRNO | $retcode_errno),"
					}
				}
			}
			default {
				return -code error "Unknown: $word"
			}
		}
	}

	return $output
}

proc ::seccomp_bpf::generate {handle} {
	set output [list]
	lappend output {BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof(struct seccomp_data, arch))), /* Load architecture */}
	foreach platform $::seccomp_bpf::_platforms($handle) {
		set platform_id "AUDIT_ARCH_[string toupper $platform]"

		lappend output "BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, $platform_id, @@platform_${platform}@@, 0),"
	}
	lappend output {*}[::seccomp_bpf::_eval $handle $platform "return trap"]

	foreach platform $::seccomp_bpf::_platforms($handle) {
		if {![dict exists $::seccomp_bpf::_platform_code($handle) $platform]} {
			error "The platform $platform must have code defined for it."
		}

		set code [dict get $::seccomp_bpf::_platform_code($handle) $platform]

		lappend output {*}[::seccomp_bpf::_eval $handle $platform $code "platform_$platform"]
	}

	set output [_fix_labels $output]

	return [join $output "\n"]
}

proc ::seccomp_bpf::code {handle platform code} {
	dict set ::seccomp_bpf::_platform_code($handle) $platform $code
}

proc ::seccomp_bpf::set_variable {handle variable value} {
	dict set ::seccomp_bpf::_variables($handle) $variable $value
}
# ----

set handle [::seccomp_bpf::new]

if {[llength $argv] == 0} {
	puts stderr "Usage: generate-seccomp-filter <filter-file> \[<platformName> <platformSyscallTable> \[<platformName> <platformSyscallTable>\]...\]"
	exit 1
}

set seccompFile [lindex $argv 0]
set argv [lrange $argv 1 end]
foreach {platform file} $argv {
	if {$file eq ""} {
		set data ""
	} else {
		set data [read [open $file]]
	}
	::seccomp_bpf::init_platform $handle $platform $data
}

set seccompData [read [open $seccompFile]]

for {set idx 0} {$idx < [llength $seccompData]} {incr idx} {
	set platformOrCommand [lindex $seccompData $idx]
	switch -exact $platformOrCommand {
		"set" {
			incr idx
			set variable [lindex $seccompData $idx]
			incr idx
			set value [lindex $seccompData $idx]
			::seccomp_bpf::set_variable $handle $variable $value
		}
		default {
			set platform $platformOrCommand

			incr idx
			set code [lindex $seccompData $idx]

			::seccomp_bpf::code $handle $platform $code
		}
	}
}

puts [::seccomp_bpf::generate $handle]

exit 0

Added scripts/fossil-as-user/secure-wrap.c.



























































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
/*
 * Simple wrapper that does chroot, seccomp,
 * and sets resource limits, before dropping privileges
 */

#define _XOPEN_SOURCE 1

#include <linux/seccomp.h>
#include <linux/filter.h>
#include <sys/resource.h>
#include <linux/audit.h>
#include <sys/ptrace.h>
#include <sys/socket.h>
#include <sys/prctl.h>
#include <sys/types.h>
#include <sys/time.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stddef.h>
#include <limits.h>
#include <errno.h>
#include <stdio.h>

extern char **environ;

#define SECURE_WRAP_MAX_ID 5242880LU
#define SECURE_WRAP_BASE_ID (1024LU * 1024LU)

#define check(command) if ((command) != 0) { perror(#command); return(1); }

#define error_eperm 1

int enable_seccomp(void) {
	struct sock_fprog filter;
	struct sock_filter rules[] = {
#include "filter.h"
	};

	filter.len = sizeof(rules) / sizeof(*rules);
	filter.filter = rules;

	check(prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0))
	check(prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &filter));

	return(0);
}

int main(int argc, char **argv) {
	const char *directory, *program;
	char *id_string;
	unsigned long id;
	struct rlimit limit;
	unsigned int tmp_fd;

	if (argc < 4) {
		fprintf(stderr, "usage: secure-wrap <id> <directory> <program> [<args>...]\n");

		return(2);
	}

	id_string = argv[1];
	id = strtoul(id_string, NULL, 0);
	argc--;
	argv++;

	if (id > SECURE_WRAP_MAX_ID) {
		fprintf(stderr, "error: id may not exceed %lu\n", SECURE_WRAP_MAX_ID);

		return(4);
	}

	directory = argv[1];
	argc--;
	argv++;

	program = argv[1];
	argc--;
	argv++;

	/*
	 * chroot
	 */
	check(chdir(directory));
	check(chroot(directory));
	check(chdir("/"));

	/*
	 * Renice to avoid being able to use a lot of CPU
	 */
	setpriority(PRIO_PROCESS, 0, 19);

	/*
	 * Close all file descriptors
	 */
	limit.rlim_cur = 8192;
	limit.rlim_max = 8192;
	check(getrlimit(RLIMIT_NOFILE, &limit));
	for (tmp_fd = 3; tmp_fd < limit.rlim_max; tmp_fd++) {
		if (tmp_fd > INT_MAX) {
			return(3);
		}
		close(tmp_fd);
	}

	/*
	 * Set resource limits
	 */
	/**
	 ** Disallow many kinds of resources entirely
	 **/
	limit.rlim_cur = 0;
	limit.rlim_max = 0;
	check(setrlimit(RLIMIT_CORE, &limit));
	check(setrlimit(RLIMIT_LOCKS, &limit));
	check(setrlimit(RLIMIT_MEMLOCK, &limit));
	check(setrlimit(RLIMIT_MSGQUEUE, &limit));

	/**
	 ** Allow a reasonable number of file descriptors
	 **/
	limit.rlim_cur = 32;
	limit.rlim_max = 32;
	check(setrlimit(RLIMIT_NOFILE, &limit));

	/**
	 ** Allow a reasonable number of processes
	 **/
	limit.rlim_cur = 10;
	limit.rlim_max = 10;
	check(setrlimit(RLIMIT_NPROC, &limit));

	/**
	 ** Allow a reasonable amount of CPU time
	 **/
	limit.rlim_cur = 90;
	limit.rlim_max = 90;
	check(setrlimit(RLIMIT_CPU, &limit));

	/**
	 ** Allow a reasonable amount of RAM
	 **/
	limit.rlim_cur = 1024 * 1024 * 64LU;
	limit.rlim_max = 1024 * 1024 * 64LU;
	check(setrlimit(RLIMIT_DATA, &limit));
	check(setrlimit(RLIMIT_RSS, &limit));
	check(setrlimit(RLIMIT_STACK, &limit));

	limit.rlim_cur = 1024 * 1024 * 1024LU;
	limit.rlim_max = 1024 * 1024 * 1024LU;
	check(setrlimit(RLIMIT_AS, &limit));

	/*
	 * Drop privileges
	 */
	check(setgid(SECURE_WRAP_BASE_ID + id));
	check(setuid(SECURE_WRAP_BASE_ID + id));

	/*
	 * Install seccomp filter
	 */
	check(enable_seccomp());

	/*
	 * Execute program
	 */
	check(execve(program, argv, environ));

	/*
	 * Failed to execute program
	 */
	return(1);
}

Added scripts/fossil-as-user/suid-fossil.

























































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
#! /usr/bin/php
<?php

include(dirname(__FILE__) . '/../include.php');

function get_user_id_from_username($username) {
	$sql = "SELECT * FROM users WHERE username = :username";
	$bind = array(
		'username' => $username
	);

	if ($result = Nano_Db::query($sql, $bind)) {
		foreach ($result as $user) {
			return($user['id']);
		}
	}

	return(null);
}

function get_user_name($userid) {
	$username = getenv('FLINT_USERNAME');
	if (isset($username) && $username) {
		return $username;
	}

	$sql = "SELECT * FROM users WHERE id = :id";
	$bind = array(
		'id' => $userid
	);

	if ($result = Nano_Db::query($sql, $bind)) {
		foreach ($result as $user) {
			return($user['username']);
		}
	}

	return(null);
}

function get_user_id($argv) {
	/*
	 * Pick out the username from something that has been
	 * explicitly set
	 */
	$userid = getenv('FLINT_USERID');
	if (isset($userid) && $userid) {
		return($userid);
	}

	$username = getenv('FLINT_USERNAME');
	if (isset($username) && $username) {
		$userid = get_user_id_from_username($username);
		if (isset($userid)) {
			return($userid);
		}
	}

	/*
	 * Pick out the username from the path we are running
	 */
	if ($argv[1] === 'repository') {
		$username = end(preg_split("/\//", getcwd()));

		$userid = get_user_id_from_username($username);
		if (isset($userid)) {
			return($userid);
		}
	}

	return(null);
}

function mkdir_p($dir) {
	if (file_exists($dir)) {
		return;
	}

	mkdir($dir, 0755, TRUE);

	return;
}

function unlink_f($file) {
	if (!file_exists($file)) {
		return;
	}

	unlink($file);
}

function log_message($message) {
error_log($message);
	$fd = fopen("/var/tmp/flint-suid-fossil.log", "a+");
	fwrite($fd, $message . "\n");
	fclose($fd);
}

function exec_log($command) {
	log_message("Running: {$command}");
	return(exec($command));
}

$fossil_config = array();
$fossil_config_file = dirname(__FILE__) . '/../../config/fossil.cnf';
if (file_exists($fossil_config_file)) {
	$fossil_config = parse_ini_file($fossil_config_file);
}

if (isset($fossil_config['use_suid']) && $fossil_config['use_suid'] === '1') {
	$use_suid = true;
} else {
	$use_suid = false;
}

if (isset($fossil_config['binary'])) {
	$fossil_binary_real = $fossil_config['binary'];
} else {
	$fossil_binary_real = '/usr/local/bin/fossil';
}

if (isset($fossil_config['root_link_prefix'])) {
	$root_link_prefix = $fossil_config['root_link_prefix'];
} else {
	$root_link_prefix = '';
}

$userid = get_user_id($argv);

if (isset($userid)) {
	$username = get_user_name($userid);

	$user_directory = dirname(__FILE__) . "/../../repos/{$username}";
	$repo_directory = $user_directory . "/data";

	$work_dir = '/root';
	$home_dir = $work_dir . '/home';

	$work_dir_outside = $user_directory . $work_dir;
	$home_dir_outside = $user_directory . $home_dir;

	$fossil_binary = $work_dir . '/bin/' . basename($fossil_binary_real);
	$fossil_binary_outside = $user_directory . $fossil_binary;
	$fossil_binary_symlink = dirname($fossil_binary_outside) . "/fossil";

	$real_user_id = (1024 * 1024) + $userid;
	$current_user_id = posix_getuid();
}

if ($use_suid) {
	if (!isset($userid)) {
		exit(1);
	}

	/*
	 * If the binary has not been setup, take this as a cue that the project
	 * directory needs to be setup.
	 */
	$upgrade_required = false;
	if (!file_exists($fossil_binary_outside)) {
		$upgrade_required = true;
	}

	if (!file_exists($fossil_binary_symlink)) {
		$upgrade_required = true;
	}
		
	if ($upgrade_required) {
		log_message("Upgrading {$user_directory} to {$fossil_binary_real}");

		mkdir_p(dirname($fossil_binary_outside));
		mkdir_p($home_dir_outside);

		$fossil_binary_resolved = realpath($fossil_binary_real);
		if (!$fossil_binary_resolved) {
			exit(1);
		}

		/*
		 * Create the Fossil named either after the tail of its
		 * external name or the version number if the name
		 * is just "fossil" (since we will symlink it into place)
		 */
		if (basename($fossil_binary_outside) === 'fossil') {
			$fossil_version = `$fossil_binary_resolved version | sed 's@^.* version @@;s@ .*$@@'`;
			$fossil_binary_outside = $fossil_binary_outside . '-' . $fossil_version;
		}

		unlink_f($fossil_binary_outside);
		link($fossil_binary_resolved, $fossil_binary_outside);

		unlink_f($fossil_binary_symlink);
		symlink(basename($fossil_binary_outside), $fossil_binary_symlink);

		/*
		 * Setup a usable environment
		 */
		mkdir_p($user_directory);
		mkdir_p($user_directory . '/etc');

		/**
		 ** User/Group Lookup
		 **/
		$fd = fopen($user_directory . '/etc/passwd', 'w');
		fwrite($fd, "{$username}:x:{$real_user_id}:{$real_user_id}::{$home_dir}:{$work_dir}/bin/sh\n");
		fclose($fd);

		$fd = fopen($user_directory . '/etc/group', 'w');
		fwrite($fd, "{$username}:x:{$real_user_id}:\n");
		fclose($fd);

		/**
		 ** DNS
		 **/
		unlink_f($user_directory . '/etc/resolv.conf');
		link('/etc/resolv.conf', $user_directory . '/etc/resolv.conf');

		/**
		 ** SSL
		 **/
		mkdir_p($user_directory . '/etc/ssl/certs');
		system('rm -f ' . escapeshellarg($user_directory . '/etc/ssl/certs/') . '*');
		system('cp -L /etc/ssl/certs/????????.? ' . escapeshellarg($user_directory . '/etc/ssl/certs/'));

		/**
		 ** Temporary storage
		 **/
		mkdir_p($user_directory . '/tmp');
		chmod($user_directory . '/tmp', 01777);

		/**
		 ** Device nodes
		 **/
		mkdir_p($user_directory . '/dev');
		system("cp -l {$root_link_prefix}/dev/null {$root_link_prefix}/dev/urandom {$root_link_prefix}/dev/random {$root_link_prefix}/dev/zero " . escapeshellarg($root_link_prefix . '/' . $user_directory . '/dev'));

		/*
		 * Ensure that the directory has the appropriate permissions
		 */
		mkdir_p($repo_directory);

		putenv("PATH=/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin:/usr/local/sbin");

		exec_log('setfacl -RP -m u:' . $real_user_id . ':rwx ' . escapeshellarg($repo_directory));
		exec_log('setfacl   -m d:u:' . $real_user_id . ':rwx ' . escapeshellarg($repo_directory));
		exec_log('setfacl -RP -m m::rwx  -m u:' . $current_user_id . ':rwx ' . escapeshellarg($repo_directory));
		exec_log('setfacl   -m d:m::rwx -m d:u:' . $current_user_id . ':rwx ' . escapeshellarg($repo_directory));
		exec_log('setfacl -m   u:' . $real_user_id . ':rwx ' . escapeshellarg($home_dir_outside));
		exec_log('setfacl -m d:u:' . $real_user_id . ':rwx ' . escapeshellarg($home_dir_outside));
		exec_log('setfacl -m   u:' . $current_user_id . ':rwx ' . escapeshellarg($home_dir_outside));
		exec_log('setfacl -m d:u:' . $current_user_id . ':rwx ' . escapeshellarg($home_dir_outside));
	}

	$command = escapeshellarg(dirname(__FILE__) . "/secure-wrap") . " " . escapeshellarg($userid) . " " . escapeshellarg($user_directory) . " " . escapeshellarg($fossil_binary);

	putenv("USER={$username}");
	putenv("HOME={$home_dir}");
} else {
	$downgrade_required = false;
	if (isset($fossil_binary_outside) && file_exists($fossil_binary_outside)) {
		$downgrade_required = true;
	}
	if (isset($fossil_binary_symlink) && file_exists($fossil_binary_symlink)) {
		$downgrade_required = true;
	}
	if ($downgrade_required) {
		log_message("Downgrading {$user_directory} from {$fossil_binary_real}");

		unlink_f($fossil_binary_outside);
		unlink_f($fossil_binary_symlink);

		putenv("PATH=/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin:/usr/local/sbin");

		exec_log('setfacl -RP -x   u:' . $real_user_id . ' ' . escapeshellarg($repo_directory));
		exec_log('setfacl -RP -x d:u:' . $real_user_id . ' ' . escapeshellarg($repo_directory));
		exec_log('setfacl -RP -m   m::rwx   -m u:' . $current_user_id . ':rwx ' . escapeshellarg($repo_directory));
		exec_log('setfacl -RP -m d:m::rwx -m d:u:' . $current_user_id . ':rwx ' . escapeshellarg($repo_directory));
		exec_log('setfacl -RP -x   u:' . $real_user_id . ' ' . escapeshellarg($home_dir_outside));
		exec_log('setfacl -RP -x d:u:' . $real_user_id . ' ' . escapeshellarg($home_dir_outside));
		exec_log('setfacl -RP -m   u:' . $current_user_id . ':rwx ' . escapeshellarg($home_dir_outside));
		exec_log('setfacl -RP -m d:u:' . $current_user_id . ':rwx ' . escapeshellarg($home_dir_outside));
	}

	$command = escapeshellarg($fossil_binary_real);
}

foreach (array_slice($argv, 1) as $arg) {
	$command = $command . " " . escapeshellarg($arg);
}
$command = trim($command);

if (getenv("SERVER_PORT") === '443') {
	putenv("HTTPS=on");
}

log_message("Running: >> {$command}");
passthru($command, $rc);
exit($rc);

?>

Changes to scripts/include.php.

1
2
3
4
5
6
7
8
9
10
11
<?php

$_SERVER['DOCUMENT_ROOT'] = dirname(__FILE__);

date_default_timezone_set('America/Detroit');

function __autoload($class)
{
    $class = strtolower(str_replace('_', '/', $class));
    require_once('../' . $class . '.php');
}




|




|

1
2
3
4
5
6
7
8
9
10
11
<?php

$_SERVER['DOCUMENT_ROOT'] = dirname(__FILE__);

date_default_timezone_set('UTC');

function __autoload($class)
{
    $class = strtolower(str_replace('_', '/', $class));
    require_once(dirname(__FILE__) . '/../' . $class . '.php');
}

Changes to scripts/rebuild.php.

1
2
3
4
5
6
7





8
9




<?php

$repositories = glob('../repos/*/*.fossil');

foreach ($repositories as $repository) {
    echo $repository . "\n";
    system("fossil rebuild -R {$repository}");





    echo "\n";
}






|

|
|
|
>
>
>
>
>
|
|
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php

include('include.php');

$sql = "SELECT * FROM users"; 
if ($result = Nano_Db::query($sql)) {
	foreach ($result as $user) {
		$username = $user['username'];
		echo "Processing User: {$username}\n";
		$fossil = new Nano_Fossil($user);
		$result = $fossil->rebuildAllRepos();
		if (!$result) {
			echo "Failed!\n";
		}
	}
}

?>