Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/pkg
Path: blob/main/libpkg/lua.c
2065 views
1
/*-
2
* Copyright (c) 2019-2022 Baptiste Daroussin <[email protected]>
3
* Copyright (c) 2023 Serenity Cyber Security, LLC
4
* Author: Gleb Popov <[email protected]>
5
* All rights reserved.
6
*
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions
9
* are met:
10
* 1. Redistributions of source code must retain the above copyright
11
* notice, this list of conditions and the following disclaimer
12
* in this position and unchanged.
13
* 2. Redistributions in binary form must reproduce the above copyright
14
* notice, this list of conditions and the following disclaimer in the
15
* documentation and/or other materials provided with the distribution.
16
*
17
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
18
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
21
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
*/
28
29
#include "pkg_config.h"
30
31
#ifdef HAVE_CAPSICUM
32
#include <sys/capsicum.h>
33
#endif
34
35
#include <sys/stat.h>
36
#include <sys/mman.h>
37
#include <sys/wait.h>
38
39
#include <dirent.h>
40
#include <errno.h>
41
#include <fcntl.h>
42
#include <spawn.h>
43
#include <stdbool.h>
44
#include <unistd.h>
45
#include <xstring.h>
46
47
#include "private/pkg.h"
48
#include "private/event.h"
49
#include "private/lua.h"
50
51
#ifndef DEFFILEMODE
52
#define DEFFILEMODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)
53
#endif
54
55
extern char **environ;
56
57
lua_CFunction
58
stack_dump(lua_State *L)
59
{
60
int i;
61
int top = lua_gettop(L);
62
xstring *stack;
63
char *stackstr;
64
65
stack = xstring_new();
66
67
fputs("\nLua Stack\n---------\n"
68
"\tType Data\n\t-----------\n", stack->fp);
69
70
for (i = 1; i <= top; i++) { /* repeat for each level */
71
int t = lua_type(L, i);
72
fprintf(stack->fp, "%i", i);
73
switch (t) {
74
case LUA_TSTRING: /* strings */
75
fprintf(stack->fp, "\tString: `%s'\n", lua_tostring(L, i));
76
break;
77
case LUA_TBOOLEAN: /* booleans */
78
fprintf(stack->fp, "\tBoolean: %s", lua_toboolean(L, i) ? "\ttrue\n" : "\tfalse\n");
79
break;
80
case LUA_TNUMBER: /* numbers */
81
fprintf(stack->fp, "\tNumber: %g\n", lua_tonumber(L, i));
82
break;
83
default: /* other values */
84
fprintf(stack->fp, "\tOther: %s\n", lua_typename(L, t));
85
break;
86
}
87
}
88
stackstr = xstring_get(stack);
89
pkg_emit_error("%s\n", stackstr);
90
free(stackstr);
91
92
return (0);
93
}
94
95
int
96
lua_print_msg(lua_State *L)
97
{
98
int n = lua_gettop(L);
99
luaL_argcheck(L, n == 1, n > 1 ? 2 : n,
100
"pkg.print_msg takes exactly one argument");
101
const char* str = luaL_checkstring(L, 1);
102
lua_getglobal(L, "msgfd");
103
int fd = lua_tointeger(L, -1);
104
105
dprintf(fd, "%s\n", str);
106
107
return (0);
108
}
109
110
111
static const char**
112
luaL_checkarraystrings(lua_State *L, int arg) {
113
const char **ret;
114
lua_Integer n, i;
115
int t;
116
int abs_arg = lua_absindex(L, arg);
117
luaL_checktype(L, abs_arg, LUA_TTABLE);
118
n = lua_rawlen(L, abs_arg);
119
ret = lua_newuserdata(L, (n+1)*sizeof(char*));
120
for (i=0; i<n; i++) {
121
t = lua_rawgeti(L, abs_arg, i+1);
122
if (t == LUA_TNIL)
123
break;
124
luaL_argcheck(L, t == LUA_TSTRING, arg, "expected array of strings");
125
ret[i] = lua_tostring(L, -1);
126
lua_pop(L, 1);
127
}
128
ret[i] = NULL;
129
return ret;
130
}
131
132
int
133
lua_exec(lua_State *L)
134
{
135
int r, pstat;
136
posix_spawn_file_actions_t action;
137
int stdin_pipe[2] = {-1, -1};
138
pid_t pid;
139
const char **argv;
140
int n = lua_gettop(L);
141
luaL_argcheck(L, n == 1, n > 1 ? 2 : n,
142
"pkg.exec takes exactly one argument");
143
144
#ifdef HAVE_CAPSICUM
145
unsigned int capmode;
146
if (cap_getmode(&capmode) == 0 && capmode > 0) {
147
return (luaL_error(L, "pkg.exec not available in sandbox"));
148
}
149
#endif
150
if (pipe(stdin_pipe) < 0)
151
return (EPKG_FATAL);
152
153
posix_spawn_file_actions_init(&action);
154
posix_spawn_file_actions_adddup2(&action, stdin_pipe[0], STDIN_FILENO);
155
posix_spawn_file_actions_addclose(&action, stdin_pipe[1]);
156
157
argv = luaL_checkarraystrings(L, 1);
158
if (0 != (r = posix_spawnp(&pid, argv[0], &action, NULL,
159
(char*const*)argv, environ))) {
160
lua_pushnil(L);
161
lua_pushstring(L, strerror(r));
162
lua_pushinteger(L, r);
163
return 3;
164
}
165
while (waitpid(pid, &pstat, 0) == -1) {
166
if (errno != EINTR) {
167
lua_pushnil(L);
168
lua_pushstring(L, strerror(r));
169
lua_pushinteger(L, r);
170
return 3;
171
}
172
}
173
174
if (WEXITSTATUS(pstat) != 0) {
175
lua_pushnil(L);
176
lua_pushstring(L, "Abnormal termination");
177
lua_pushinteger(L, r);
178
return 3;
179
}
180
181
posix_spawn_file_actions_destroy(&action);
182
183
if (stdin_pipe[0] != -1)
184
close(stdin_pipe[0]);
185
if (stdin_pipe[1] != -1)
186
close(stdin_pipe[1]);
187
lua_pushinteger(L, pid);
188
return 1;
189
}
190
191
int
192
lua_pkg_copy(lua_State *L)
193
{
194
int n = lua_gettop(L);
195
luaL_argcheck(L, n == 2, n > 2 ? 3 : n,
196
"pkg.copy takes exactly two arguments");
197
const char* src = luaL_checkstring(L, 1);
198
const char* dst = luaL_checkstring(L, 2);
199
struct stat s1;
200
int fd1, fd2;
201
struct timespec ts[2];
202
203
#ifdef HAVE_CHFLAGSAT
204
bool install_as_user = (getenv("INSTALL_AS_USER") != NULL);
205
#endif
206
207
lua_getglobal(L, "rootfd");
208
int rootfd = lua_tointeger(L, -1);
209
210
if (fstatat(rootfd, RELATIVE_PATH(src), &s1, 0) == -1) {
211
lua_pushinteger(L, 2);
212
return (1);
213
}
214
fd1 = openat(rootfd, RELATIVE_PATH(src), O_RDONLY, DEFFILEMODE);
215
if (fd1 == -1) {
216
lua_pushinteger(L, 2);
217
return (1);
218
}
219
220
fd2 = openat(rootfd, RELATIVE_PATH(dst), O_RDWR | O_CREAT | O_TRUNC | O_EXCL, s1.st_mode);
221
if (fd2 == -1) {
222
lua_pushinteger(L, 2);
223
return (1);
224
}
225
226
if (!pkg_copy_file(fd1, fd2)) {
227
lua_pushinteger(L, 2);
228
return (1);
229
}
230
if (fchown(fd2, s1.st_uid, s1.st_gid) == -1) {
231
lua_pushinteger(L, 2);
232
return (1);
233
}
234
235
fsync(fd2);
236
close(fd1);
237
close(fd2);
238
239
#ifdef HAVE_STRUCT_STAT_ST_MTIM
240
ts[0] = s1.st_atim;
241
ts[1] = s1.st_mtim;
242
#else
243
#if defined(_DARWIN_C_SOURCE) || defined(__APPLE__)
244
ts[0] = s1.st_atimespec;
245
ts[1] = s1.st_mtimespec;
246
#else
247
ts[0].tv_sec = s1.st_atime;
248
ts[0].tv_nsec = 0;
249
ts[1].tv_sec = s1.st_mtime;
250
ts[1].tv_nsec = 0;
251
#endif
252
#endif
253
254
if (set_attrsat(rootfd, RELATIVE_PATH(dst), s1.st_mode, s1.st_uid,
255
s1.st_gid, &ts[0], &ts[1]) != EPKG_OK) {
256
lua_pushinteger(L, -1);
257
return (1);
258
}
259
260
#ifdef HAVE_CHFLAGSAT
261
if (!install_as_user && s1.st_flags != 0) {
262
if (chflagsat(rootfd, RELATIVE_PATH(dst),
263
s1.st_flags, AT_SYMLINK_NOFOLLOW) == -1) {
264
pkg_fatal_errno("Fail to chflags %s", dst);
265
lua_pushinteger(L, -1);
266
return (1);
267
}
268
}
269
#endif
270
return (0);
271
}
272
273
int
274
lua_pkg_filecmp(lua_State *L)
275
{
276
int n = lua_gettop(L);
277
luaL_argcheck(L, n == 2, n > 2 ? 3 : n,
278
"pkg.filecmp takes exactly two arguments");
279
const char* file1 = luaL_checkstring(L, 1);
280
const char* file2 = luaL_checkstring(L, 2);
281
char *buf1, *buf2;
282
struct stat s1, s2;
283
int fd1, fd2;
284
int ret = 0;
285
286
lua_getglobal(L, "rootfd");
287
int rootfd = lua_tointeger(L, -1);
288
289
if (fstatat(rootfd, RELATIVE_PATH(file1), &s1, 0) == -1) {
290
lua_pushinteger(L, 2);
291
return (1);
292
}
293
if (fstatat(rootfd, RELATIVE_PATH(file2), &s2, 0) == -1) {
294
lua_pushinteger(L, 2);
295
return (1);
296
}
297
if (s1.st_size != s2.st_size) {
298
lua_pushinteger(L, 1);
299
return (1);
300
}
301
fd1 = openat(rootfd, RELATIVE_PATH(file1), O_RDONLY, DEFFILEMODE);
302
if (fd1 == -1) {
303
lua_pushinteger(L, 2);
304
return (1);
305
}
306
buf1 = mmap(NULL, s1.st_size, PROT_READ, MAP_SHARED, fd1, 0);
307
close(fd1);
308
if (buf1 == NULL) {
309
lua_pushinteger(L, -1);
310
return (1);
311
}
312
fd2 = openat(rootfd, RELATIVE_PATH(file2), O_RDONLY, DEFFILEMODE);
313
if (fd2 == -1) {
314
lua_pushinteger(L, 2);
315
return (1);
316
}
317
318
buf2 = mmap(NULL, s2.st_size, PROT_READ, MAP_SHARED, fd2, 0);
319
close(fd2);
320
if (buf2 == NULL) {
321
lua_pushinteger(L, -1);
322
return (1);
323
}
324
if (memcmp(buf1, buf2, s1.st_size) != 0)
325
ret = 1;
326
327
munmap(buf1, s1.st_size);
328
munmap(buf2, s2.st_size);
329
330
lua_pushinteger(L, ret);
331
return (1);
332
}
333
334
int
335
lua_pkg_symlink(lua_State *L)
336
{
337
int n = lua_gettop(L);
338
luaL_argcheck(L, n == 2, n > 2 ? 3 : n,
339
"pkg.symlink takes exactly two arguments");
340
const char *from = luaL_checkstring(L, 1);
341
const char *to = luaL_checkstring(L, 2);
342
lua_getglobal(L, "rootfd");
343
int rootfd = lua_tointeger(L, -1);
344
if (symlinkat(from, rootfd, RELATIVE_PATH(to)) == -1)
345
return (luaL_fileresult(L, 0, from));
346
return (1);
347
}
348
349
int
350
lua_prefix_path(lua_State *L)
351
{
352
int n = lua_gettop(L);
353
luaL_argcheck(L, n == 1, n > 1 ? 2 : n,
354
"pkg.prefix_path takes exactly one argument");
355
const char *str = luaL_checkstring(L, 1);
356
lua_getglobal(L, "package");
357
struct pkg *p = lua_touserdata(L, -1);
358
359
char path[MAXPATHLEN];
360
path[0] = '\0';
361
362
if (*str == '/') {
363
strlcat(path, str, MAXPATHLEN);
364
} else {
365
strlcat(path, p->prefix, MAXPATHLEN);
366
strlcat(path, "/", MAXPATHLEN);
367
strlcat(path, str, MAXPATHLEN);
368
}
369
370
lua_pushstring(L, path);
371
return (1);
372
}
373
374
int
375
lua_stat(lua_State *L)
376
{
377
int n = lua_gettop(L);
378
luaL_argcheck(L, n == 1, n > 1 ? 2 : n,
379
"pkg.stat takes exactly one argument");
380
const char *path = RELATIVE_PATH(luaL_checkstring(L, 1));
381
lua_getglobal(L, "rootfd");
382
int rootfd = lua_tointeger(L, -1);
383
struct stat s;
384
const char *type = "unknown";
385
386
if (fstatat(rootfd, path, &s, AT_SYMLINK_NOFOLLOW) == -1) {
387
return lua_pushnil(L), 1;
388
}
389
390
lua_settop(L, 2);
391
if (!lua_istable(L, 2))
392
lua_newtable(L);
393
394
lua_pushinteger(L, s.st_size);
395
lua_setfield(L, -2, "size");
396
lua_pushinteger(L, s.st_uid);
397
lua_setfield(L, -2, "uid");
398
lua_pushinteger(L, s.st_gid);
399
lua_setfield(L, -2, "gid");
400
if (S_ISREG(s.st_mode))
401
type = "reg";
402
else if (S_ISDIR(s.st_mode))
403
type = "dir";
404
else if (S_ISCHR(s.st_mode))
405
type = "chr";
406
else if (S_ISLNK(s.st_mode))
407
type = "lnk";
408
else if (S_ISSOCK(s.st_mode))
409
type = "sock";
410
else if (S_ISBLK(s.st_mode))
411
type = "blk";
412
else if (S_ISFIFO(s.st_mode))
413
type = "fifo";
414
lua_pushstring(L, type);
415
lua_setfield(L, -2, "type");
416
417
return (1);
418
}
419
420
/* stolen from lua.c */
421
void
422
lua_args_table(lua_State *L, char **argv, int argc)
423
{
424
lua_createtable(L, argc, 1);
425
for (int i = 0; i < argc; i++) {
426
lua_pushstring(L, argv[i]);
427
/* lua starts counting by 1 */
428
lua_rawseti(L, -2, i + 1);
429
}
430
lua_setglobal(L, "arg");
431
}
432
433
434
/*
435
* this is a copy of lua code to be able to override open
436
* merge of newprefile and newfile
437
*/
438
439
static int
440
my_iofclose(lua_State *L)
441
{
442
luaL_Stream *p = ((luaL_Stream *)luaL_checkudata(L, 1, LUA_FILEHANDLE));
443
int res = fclose(p->f);
444
return (luaL_fileresult(L, (res == 0), NULL));
445
}
446
447
static luaL_Stream *
448
newfile(lua_State *L) {
449
luaL_Stream *p = (luaL_Stream *)lua_newuserdata(L, sizeof(luaL_Stream));
450
p->f = NULL;
451
p->closef = &my_iofclose;
452
luaL_setmetatable(L, LUA_FILEHANDLE);
453
return (p);
454
}
455
456
static int
457
lua_io_open(lua_State *L)
458
{
459
const char *filename = luaL_checkstring(L, 1);
460
const char *mode = luaL_optstring(L, 2, "r");
461
lua_getglobal(L, "rootfd");
462
int rootfd = lua_tointeger(L, -1);
463
int oflags;
464
luaL_Stream *p = newfile(L);
465
const char *md = mode;
466
luaL_argcheck(L, checkflags(md, &oflags), 2, "invalid mode");
467
int fd = openat(rootfd, RELATIVE_PATH(filename), oflags, DEFFILEMODE);
468
if (fd == -1)
469
return (luaL_fileresult(L, 0, filename));
470
p->f = fdopen(fd, mode);
471
return ((p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1);
472
}
473
474
static int
475
lua_os_remove(lua_State *L) {
476
const char *filename = RELATIVE_PATH(luaL_checkstring(L, 1));
477
lua_getglobal(L, "rootfd");
478
int rootfd = lua_tointeger(L, -1);
479
int flag = 0;
480
struct stat st;
481
482
if (fstatat(rootfd, filename, &st, AT_SYMLINK_NOFOLLOW) == -1)
483
return (luaL_fileresult(L, 1, NULL));
484
485
if (S_ISDIR(st.st_mode))
486
flag = AT_REMOVEDIR;
487
488
return (luaL_fileresult(L, unlinkat(rootfd, filename, flag) == 0, NULL));
489
}
490
491
static int
492
lua_os_rename(lua_State *L)
493
{
494
const char *fromname = RELATIVE_PATH(luaL_checkstring(L, 1));
495
const char *toname = RELATIVE_PATH(luaL_checkstring(L, 2));
496
lua_getglobal(L, "rootfd");
497
int rootfd = lua_tointeger(L, -1);
498
return luaL_fileresult(L, renameat(rootfd, fromname, rootfd, toname) == 0, NULL);
499
}
500
501
static int
502
lua_os_execute(lua_State *L)
503
{
504
return (luaL_error(L, "os.execute not available"));
505
}
506
507
static int
508
lua_os_exit(lua_State *L)
509
{
510
return (luaL_error(L, "os.exit not available"));
511
}
512
513
void
514
lua_override_ios(lua_State *L, bool sandboxed)
515
{
516
lua_getglobal(L, "io");
517
lua_pushcfunction(L, lua_io_open);
518
lua_setfield(L, -2, "open");
519
520
lua_getglobal(L, "os");
521
lua_pushcfunction(L, lua_os_remove);
522
lua_setfield(L, -2, "remove");
523
lua_pushcfunction(L, lua_os_rename);
524
lua_setfield(L, -2, "rename");
525
if (sandboxed) {
526
lua_pushcfunction(L, lua_os_execute);
527
lua_setfield(L, -2, "execute");
528
}
529
lua_pushcfunction(L, lua_os_exit);
530
lua_setfield(L, -2, "exit");
531
}
532
533
int
534
lua_readdir(lua_State *L)
535
{
536
int n = lua_gettop(L);
537
luaL_argcheck(L, n == 1, n > 1 ? 2 : n,
538
"pkg.readdir takes exactly one argument");
539
const char *path = luaL_checkstring(L, 1);
540
int fd = -1;
541
542
if (*path == '/') {
543
lua_getglobal(L, "rootfd");
544
int rootfd = lua_tointeger(L, -1);
545
if (strlen(path) > 1) {
546
fd = openat(rootfd, path +1, O_DIRECTORY);
547
} else {
548
fd = dup(rootfd);
549
}
550
} else {
551
fd = open(path, O_DIRECTORY);
552
}
553
if (fd == -1)
554
return (luaL_fileresult(L, 0, path));
555
556
DIR *dir = fdopendir(fd);
557
if (!dir)
558
return (luaL_fileresult(L, 0, path));
559
lua_newtable(L);
560
struct dirent *e;
561
int i = 0;
562
while ((e = readdir(dir))) {
563
char *name = e->d_name;
564
if (STREQ(name, ".") || STREQ(name, ".."))
565
continue;
566
lua_pushinteger(L, ++i);
567
lua_pushstring(L, name);
568
lua_settable(L, -3);
569
}
570
return 1;
571
}
572
573