sylware / lnanomsgbrd (public) (License: Affero GPLv3) (since 2024-12-11) (hash sha1)
64bits minimal noscript/basic (x)html message board with its HTTP server for linux (no-libc)
List of commits:
Subject Hash Author Date (UTC)
moved to a newer linux kernel a77e08985631e8c738d04ef9deaaaf12bae78558 Sylvain BERTRAND 2024-12-30 14:14:29
major normative references and a bit of tidying 0fb9ddf4cb87909f120fb1bf5ca32bbf1492525c Sylvain BERTRAND 2024-12-13 15:33:23
Initial commit: bugs and backdoors for everyone f53ebee69135fd2fe5629cf622bfd94b753d4532 Sylvain BERTRAND 2024-12-11 13:11:27
Commit a77e08985631e8c738d04ef9deaaaf12bae78558 - moved to a newer linux kernel
"clone3" and full "sendfile" support. Linux is now capping the transfer size
itself (actually was it ever a thing? mmmh...).
Author: Sylvain BERTRAND
Author date (UTC): 2024-12-30 14:14
Committer name: Sylvain BERTRAND
Committer date (UTC): 2024-12-30 14:14
Parent(s): 0fb9ddf4cb87909f120fb1bf5ca32bbf1492525c
Signer:
Signing key:
Signing status: N
Tree: 3e2960bd796935d73868cb31608f1262dd12c6b8
File Lines added Lines deleted
asm_support.h 14 0
cnx.c 15 64
lnanomsgbrd.S 12 0
namespace/cnx.c 4 0
namespace/ulinux.h 0 2
ulinux/archs/aarch64/sysc.h 1 0
File asm_support.h changed (mode: 100644) (index 4da44c7..8c9b0a3)
4 4 * this code is protected by the GNU affero GPLv3 * this code is protected by the GNU affero GPLv3
5 5 * author:Sylvain BERTRAND * author:Sylvain BERTRAND
6 6 */ */
7 struct lnanomsgbrd_clone_args {
8 ulinux_u64 flags;
9 ulinux_u64 pidfd;
10 ulinux_u64 child_tid;
11 ulinux_u64 parent_tid;
12 ulinux_u64 exit_signal;
13 ulinux_u64 stack; /* XXX: stack bottom */
14 ulinux_u64 stack_size;
15 ulinux_u64 tls;
16 ulinux_u64 set_tid;
17 ulinux_u64 set_tid_size;
18 ulinux_u64 cgroup;
19 };
20 extern ulinux_s64 lnanomsgbrd_clone(struct lnanomsgbrd_clone_args *args, ulinux_u64 args_bytes_n, void (*clone_entry)(void));
7 21 extern void *lnanomsgbrd_tls_get(void); extern void *lnanomsgbrd_tls_get(void);
8 22 extern void lnanomsgbrd_cleanup_and_exit_thread(void); extern void lnanomsgbrd_cleanup_and_exit_thread(void);
9 23 extern void lnanomsgbrd_spin_lock(void *p); extern void lnanomsgbrd_spin_lock(void *p);
File cnx.c changed (mode: 100644) (index 2ffd4ee..0d29b96)
... ... static bool body_part_header(struct thread_local_storage *tls)
1393 1393 } }
1394 1394 return true; return true;
1395 1395 } }
1396 /*
1397 * We emulate sendfile because it will _NOT_ function properly on our old kernel, we reuse the http message memory, cannot
1398 * sendfile 0 bytes
1399 */
1400 static sl sendfile_emulation(struct thread_local_storage *tls, si out_fd, si in_fd, u64 off /* ignored */, u64 bytes_n)
1401 {
1402 /* we first cap the amount of bytes */
1403 if (bytes_n > (THREAD_LOCAL_STORAGE_BYTES_N - TLS_HTTP_MESSAGE))
1404 bytes_n = THREAD_LOCAL_STORAGE_BYTES_N - TLS_HTTP_MESSAGE;
1405 /* only one read */
1406 u64 remaining_bytes_n = bytes_n;
1407 sl r;
1408 loop {
1409 r = read(in_fd, (u8*)tls + TLS_HTTP_MESSAGE, bytes_n);
1410 if (r != -EINTR)
1411 break;
1412 }
1413 if (ISERR(r) || r == 0)
1414 return r;
1415 /* write */
1416 u64 read_bytes_n = (u64)r;
1417 u64 remaining_bytes_n_to_write = read_bytes_n;
1418 u8 *next_write = (u8*)tls + TLS_HTTP_MESSAGE;
1419 loop { /* short write */
1420 loop {
1421 r = write(out_fd, next_write, remaining_bytes_n_to_write);
1422 if (r != -EINTR)
1423 break;
1424 }
1425 if (ISERR(r) || r == 0)
1426 return r;
1427 remaining_bytes_n_to_write -= (u64)r;
1428 if (remaining_bytes_n_to_write == 0)
1429 return (sl)read_bytes_n;
1430 next_write += (u64)r;
1431 }
1432 /* unreachable */
1433 }
1434 1396 /* access to the index file should be "synchronized" as much as possible BEFORE this call occurs */ /* access to the index file should be "synchronized" as much as possible BEFORE this call occurs */
1435 1397 static bool index_grow(u64 additional_bytes_n) static bool index_grow(u64 additional_bytes_n)
1436 1398 { {
 
... ... static void file_receive(struct thread_local_storage *tls)
1553 1515 next_write += (u64)r; next_write += (u64)r;
1554 1516 } }
1555 1517 /*-------------------------------------------------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------------------------------------------------*/
1556 /* XXX: should be sendfile here, but our kernel is too old, in_fd cannot be a socket, yet */
1557 /* now sendfile the rest of the file, with its body trailer (which we will truncate after), if we have any though */
1558 /*
1559 * XXX: BIG FAT WARNING: UPON MOVING TO THE REAL SENDFILE SYSCALL DON'T FORGET THE MAXIMUM AMOUNT OF BYTES ALLOWED
1560 * IS 0x7ffff000 (S32_MAX - one 4KiB page)
1561 */
1562 1518 remaining_body_bytes_n -= file_with_body_trailer_already_read_bytes_n; remaining_body_bytes_n -= file_with_body_trailer_already_read_bytes_n;
1563 1519 loop { /* short send file */ loop { /* short send file */
1564 if (remaining_body_bytes_n == 0) /* done, we need to truncate the body trailer */
1520 if (remaining_body_bytes_n == 0) /* done, now we need to truncate the body trailer */
1565 1521 break; break;
1566 1522 loop { loop {
1567 r = sendfile_emulation(tls, fd, tls->cnx, 0, remaining_body_bytes_n);
1523 r = sendfile(fd, tls->cnx, 0, remaining_body_bytes_n);
1568 1524 if (r != -EINTR) if (r != -EINTR)
1569 1525 break; break;
1570 1526 } }
 
... ... static void file_send(struct thread_local_storage *tls)
2005 1961 /* now, sendfile the file itself, if it is not an HTTP_METHOD_HEAD enquiry (probably for sane storage allocation) */ /* now, sendfile the file itself, if it is not an HTTP_METHOD_HEAD enquiry (probably for sane storage allocation) */
2006 1962 if (tls->request.line.method.value != HTTP_METHOD_HEAD) { if (tls->request.line.method.value != HTTP_METHOD_HEAD) {
2007 1963 u64 remaining_bytes_n_to_sendfile = (u64)(fd_statx.size); u64 remaining_bytes_n_to_sendfile = (u64)(fd_statx.size);
2008 /* XXX: linux has a max: 0x7ffff000 (S32_MAX - one 4KiB page), even in 64bits */
2009 #define LINUX_SENDFILE_BYTES_N_MAX 0x7ffff000
2010 1964 loop { /* short sendfile */ loop { /* short sendfile */
2011 1965 if (remaining_bytes_n_to_sendfile == 0) { /* never send 0 bytes since this is a end-of-connection marker */ if (remaining_bytes_n_to_sendfile == 0) { /* never send 0 bytes since this is a end-of-connection marker */
2012 1966 close(fd); close(fd);
2013 1967 return; return;
2014 1968 } }
2015 u64 bytes_n_to_sendfile;
2016 if (remaining_bytes_n_to_sendfile > bytes_n_to_sendfile)
2017 bytes_n_to_sendfile = LINUX_SENDFILE_BYTES_N_MAX; /* do cap */
2018 1969 loop { loop {
2019 r = sendfile(tls->cnx, fd, 0, bytes_n_to_sendfile);
1970 r = sendfile(tls->cnx, fd, 0, remaining_bytes_n_to_sendfile);
2020 1971 if (r != -EINTR) if (r != -EINTR)
2021 1972 break; break;
2022 1973 } }
 
... ... static void file_send(struct thread_local_storage *tls)
2026 1977 } }
2027 1978 remaining_bytes_n_to_sendfile -= (u64)r; remaining_bytes_n_to_sendfile -= (u64)r;
2028 1979 } }
2029 #undef LINUX_SENDFILE_BYTES_N_MAX
2030 1980 } }
2031 1981 /* unreachable */ /* unreachable */
2032 1982 } }
 
... ... static void new(si cnx, struct sockaddr_in6 *peer)
2117 2067 { {
2118 2068 sl r; sl r;
2119 2069 void *thread_stack_bottom; void *thread_stack_bottom;
2120 void *thread_stack_top;
2121 2070 struct thread_local_storage *tls; /* we don't use the thread stack, and we use it to pass init data to the thread */ struct thread_local_storage *tls; /* we don't use the thread stack, and we use it to pass init data to the thread */
2071 struct clone_args args;
2122 2072 /*-------------------------------------------------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------------------------------------------------*/
2123 2073
2124 2074 // XXX: here we should do peer filtering (IPv6 or fixed IPv4) // XXX: here we should do peer filtering (IPv6 or fixed IPv4)
 
... ... static void new(si cnx, struct sockaddr_in6 *peer)
2130 2080 goto err_close_cnx; goto err_close_cnx;
2131 2081
2132 2082 thread_stack_bottom = (void*)r; thread_stack_bottom = (void*)r;
2133 thread_stack_top = (void*)((u64)r + THREAD_STACK_BYTES_N);
2134 2083 /*-------------------------------------------------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------------------------------------------------*/
2135 2084 r = mmap(0, THREAD_LOCAL_STORAGE_BYTES_N, PROT_READ | PROT_WRITE, r = mmap(0, THREAD_LOCAL_STORAGE_BYTES_N, PROT_READ | PROT_WRITE,
2136 2085 ULINUX_MAP_PRIVATE | ULINUX_MAP_ANONYMOUS, 0, 0); ULINUX_MAP_PRIVATE | ULINUX_MAP_ANONYMOUS, 0, 0);
 
... ... static void new(si cnx, struct sockaddr_in6 *peer)
2141 2090 tls->cnx = cnx; tls->cnx = cnx;
2142 2091 tls->stack = thread_stack_bottom; tls->stack = thread_stack_bottom;
2143 2092 /*-------------------------------------------------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------------------------------------------------*/
2144 /* this is fixed with clone3 in recent kernel, will write an assembly wrapper once we update the kernel */
2145 #ifdef ULINUX_ARM64
2146 r = clone( ULINUX_CLONE_VM
2093 memset(&args,0,sizeof(args));
2094 args.flags = ULINUX_CLONE_VM
2147 2095 | ULINUX_CLONE_FS | ULINUX_CLONE_FS
2148 2096 | ULINUX_CLONE_FILES | ULINUX_CLONE_FILES
2149 2097 | ULINUX_CLONE_SIGHAND | ULINUX_CLONE_SIGHAND
2150 2098 | ULINUX_CLONE_THREAD | ULINUX_CLONE_THREAD
2151 2099 | ULINUX_CLONE_SYSVSEM | ULINUX_CLONE_SYSVSEM
2152 2100 | ULINUX_CLONE_SETTLS | ULINUX_CLONE_SETTLS
2153 | ULINUX_CLONE_IO, thread_stack_top, 0, tls, 0);
2101 | ULINUX_CLONE_IO;
2102 args.stack = (u64)thread_stack_bottom;
2103 args.stack_size = THREAD_STACK_BYTES_N;
2104 args.tls = (u64)tls;
2105 #ifdef ULINUX_ARM64
2106 r = clone(&args, sizeof(args), thread_entry); /* this is a noreturn in the thread */
2154 2107 #else #else
2155 2108 #error "LNANOMSGBRD:ERROR:missing architecture clone syscall support" #error "LNANOMSGBRD:ERROR:missing architecture clone syscall support"
2156 2109 #endif #endif
2157 if (ISERR(r))
2158 goto err_munmap_tls;
2159 if (r == 0)
2160 thread_entry(); /* we waste a stack u64 slot until we write the assembly wrapper */
2161 return;
2110 /* here, this is the main thread */
2111 if (!ISERR(r))
2112 return;
2162 2113 /*-------------------------------------------------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------------------------------------------------*/
2163 2114 err_munmap_tls: err_munmap_tls:
2164 2115 munmap(tls, THREAD_LOCAL_STORAGE_BYTES_N); munmap(tls, THREAD_LOCAL_STORAGE_BYTES_N);
File lnanomsgbrd.S changed (mode: 100644) (index 3804f6d..62cd233)
16 16 #undef __ASSEMBLY__ #undef __ASSEMBLY__
17 17
18 18 #ifdef ULINUX_ARM64 #ifdef ULINUX_ARM64
19 .text
20 .global lnanomsgbrd_clone
21 .type lnanomsgbrd_clone, STT_FUNC
22 .align 2
23 lnanomsgbrd_clone:
24 mov x8,#__ULINUX_NR_clone3
25 svc 0
26 cbnz x0,0f
27 br x2
28 0:
29 ret
30 /*===========================================================================================================================*/
19 31 .text .text
20 32 .global lnanomsgbrd_tls_get .global lnanomsgbrd_tls_get
21 33 .type lnanomsgbrd_tls_get, STT_FUNC .type lnanomsgbrd_tls_get, STT_FUNC
File namespace/cnx.c changed (mode: 100644) (index 3eaf999..0c573d0)
3 3 #define body_part_header_field_line lnanommsgbrd_body_part_header_field_line #define body_part_header_field_line lnanommsgbrd_body_part_header_field_line
4 4 #define boundary_read lnanomsgbrd_boundary_read #define boundary_read lnanomsgbrd_boundary_read
5 5 #define cleanup_and_exit_thread lnanomsgbrd_cleanup_and_exit_thread #define cleanup_and_exit_thread lnanomsgbrd_cleanup_and_exit_thread
6 #define clone lnanomsgbrd_clone
7 #define clone_args lnanomsgbrd_clone_args
6 8 #define cnx_write lnanomsgbrd_cnx_write #define cnx_write lnanomsgbrd_cnx_write
7 9 #define content_disposition_parse lnanomsgbrd_content_disposition_parse #define content_disposition_parse lnanomsgbrd_content_disposition_parse
8 10 #define content_length_parse lnanomsgbrd_content_length_parse #define content_length_parse lnanomsgbrd_content_length_parse
 
56 58 #undef body_part_header_field_line #undef body_part_header_field_line
57 59 #undef boundary_read #undef boundary_read
58 60 #undef cleanup_and_exit_thread #undef cleanup_and_exit_thread
61 #undef clone
62 #undef clone_args
59 63 #undef cnx_write #undef cnx_write
60 64 #undef content_disposition_parse #undef content_disposition_parse
61 65 #undef content_length_parse #undef content_length_parse
File namespace/ulinux.h changed (mode: 100644) (index 3d8514e..dab4ab3)
76 76 #define bind(a,b,c) ulinux_sysc_3(bind,a,(sl)b,c) #define bind(a,b,c) ulinux_sysc_3(bind,a,(sl)b,c)
77 77 #define chdir(a) ulinux_sysc_1(chdir,(sl)a) #define chdir(a) ulinux_sysc_1(chdir,(sl)a)
78 78 #define chroot(a) ulinux_sysc_1(chroot,(sl)a) #define chroot(a) ulinux_sysc_1(chroot,(sl)a)
79 #define clone(a,b,c,d,e) ulinux_sysc_5(clone,(sl)a,(sl)b,(sl)c,(sl)d,(sl)e)
80 79 #define close(a) ulinux_sysc_1(close, a) #define close(a) ulinux_sysc_1(close, a)
81 80 #define cpu_to_be16_const ulinux_cpu_to_be16_const #define cpu_to_be16_const ulinux_cpu_to_be16_const
82 81 #define epoll_ctl(a,b,c,d) ulinux_sysc_4(epoll_ctl,a,b,c,(sl)d) #define epoll_ctl(a,b,c,d) ulinux_sysc_4(epoll_ctl,a,b,c,(sl)d)
 
184 183 #undef bind #undef bind
185 184 #undef chdir #undef chdir
186 185 #undef chroot #undef chroot
187 #undef clone
188 186 #undef close #undef close
189 187 #undef cpu_to_be16_const #undef cpu_to_be16_const
190 188 #undef epoll_ctl #undef epoll_ctl
File ulinux/archs/aarch64/sysc.h changed (mode: 100644) (index 6fc8551..a4d2019)
... ... long ulinux_sysc_asm_6(long a1, long a2, long a3, long a4, long a5, long a6, lon
490 490 #define __ULINUX_NR_fsconfig 431 #define __ULINUX_NR_fsconfig 431
491 491 #define __ULINUX_NR_fsmount 432 #define __ULINUX_NR_fsmount 432
492 492 #define __ULINUX_NR_fspick 433 #define __ULINUX_NR_fspick 433
493 #define __ULINUX_NR_clone3 435
493 494 /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
494 495 /* the following is a mapping to get the same on x86_64 and aarch64 */ /* the following is a mapping to get the same on x86_64 and aarch64 */
495 496 #define __ULINUX_NR_newfstatat __ULINUX_NR_fstatat #define __ULINUX_NR_newfstatat __ULINUX_NR_fstatat
Hints:
Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://rocketgit.com/user/sylware/lnanomsgbrd

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@ssh.rocketgit.com/user/sylware/lnanomsgbrd

Clone this repository using git:
git clone git://git.rocketgit.com/user/sylware/lnanomsgbrd

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a merge request:
... clone the repository ...
... make some changes and some commits ...
git push origin main