Age | Commit message (Collapse) | Author |
|
treewide: rework numeric value handling
|
|
- Parse integer literals as unsigned numeric values in order to be able
to represent the entire unsigned 64bit value range
- Stop parsing minus-prefixed integer literals as negative numbers but
treat them as separate minus operator followed by a positive integer
instead
- Only store unsigned numeric constants in bytecode
- Rework numeric comparison logic to be able to handle full 64bit
unsigned integers
- If possible, yield unsigned 64 bit results for additions
- Simplify numeric value conversion API
- Compile code with -fwrapv for defined signed overflow semantics
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
fs: implement fdopen(), file.fileno() and proc.fileno()
|
|
Implement support for opening existing file descriptors as well as acquiring
the descriptor number from open process and file handles.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
ubus: add support for async requests
|
|
Introduce a new ubus.defer() method which initiates asynchroneous requests
and invokes the completion callback passed as 4th argument once the reply
is received.
This allows multiplexing mutliple ubus requests with the same ucode VM
context / the same uloop event loop.
In case the ucode context is not running under an active uloop, the ubus
module will spawn uloop itself once the first asynchroneous request is
launched and terminate the loop once all pending requests finished.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Introduce a new, lazily allocated value registry which can be used by C
code to store values which should not be garbage collected.
The registry is a plain ucode object internally and treated as GC root
but not exposed to ucode script code, this allows it to retain references
to values which are otherwise completely unreachable from ucode scripts.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Fix various misspelling of "resource".
This commit changes the exported libucode ABI.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
No functional changes.
Fixes: ff52440 ("treewide: consolidate typedef naming")
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
The prevents garbage collecting properties which are stored in resource
value prototype objects.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Allow querying object properties on resource values. A resource value may
have a prototype object set whose properties should be enumerable.
Support that use case in the VM.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
The nl_recvmsgs() logic in uc_nl_request() incorrectly stopped reading
the socket before the netlink ACK message was handled for non-multipart
replies.
This caused subsequent requests to incorrectly receive the ACK of the
previous request, leading to a failure to receive the actual reply.
Fix this issue by continue reading the socket until either the finish
callback for multipart (dump) messages or the ack callback for non-
multipart messages was received.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Add three new functions `dirname()`, `basename()` and `lsdir()`.
The `basename()` and `dirname()` functions behave like their libc
counterparts and return the filename and directory portion of a
given path respectively. If the path argument is missing or not
a string, null is returned.
Examples:
dirname("/usr/lib") -> "/usr"
dirname("/usr/") -> "/"
dirname("usr") -> "."
dirname("/") -> "/"
dirname(".") -> "."
dirname("..") -> "."
basename("/usr/lib") -> "lib"
basename("/usr/") -> "usr"
basename("usr") -> "usr"
basename("/") -> "/"
basename(".") -> "."
basename("..") -> ".."
The `lsdir()` function returns a sorted array containing the names
of all entries within the given directory path, without the common
"." and ".." entries. If the given path is not a directory, cannot
be opened or if another system level occurs, null is returned and
`fs.error()` can be used to query details.
The function takes an optional second argument which may be either a
regular expression value or a string. In case a regular expression
is given, each directory entry is matched against it. In case a
string is provided, it is treated as wildcard (glob) pattern and
only directory entries matching the pattern are considered.
Examples:
lsdir("/sys/class/net") -> [ "eth0", "lo", "wlan0" ]
lsdir("/proc", /^[0-9]+$/) -> [ "1", "4", "12", ... ]
lsdir("/sys/class/block/", "sd?3") -> [ "sde3", "sdf3" ]
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Extract the wiphy index from the response message and use it to select
the item to merge the fragment information into.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Fix instances of misspelled "resource".
This commit breaks the exported libucode ABI.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
The "align" pragma was accidentally renamed while refactoring the
original module code.
Fixes: 402f603 ("lib: introduce struct library")
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
lib: introduce struct library
|
|
Introduce a new "struct" library which is a port of the Python 3.10 struct
module with a reduced set of API functions. It supports the same format
patterns and conversions while providing the following methods:
struct = require('struct');
buf = struct.pack("fmt", args...);
values = struct.unpack("fmt", buf);
struct_inst = struct.new("fmt");
buf = struct_inst.pack(args...);
values = struct_inst.unpack(buf);
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
While most source files contain the license text in their header, make
the repository license explicitly known by putting it here.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
lib: introduce resolver library
|
|
Subsequent requires of the same module returned the cached module instance
without increasing the refcount, leading to use-after-free on VM tear down
or garbage collection cycles.
Solve this issue by properly incrementing the refcount before returning
the cached module instance.
Fixes: #25
Fixes: 96f140b ("lib, vm: ensure that require() compiles modules only once")
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
This adds a simple, UDP-only DNS resolver library mimicking the operation of
the extended busybox nslookup applet.
Simply querying a domain name will perform A + AAAA resolving by default:
# ucode -mresolv -Rs 'printf("%.J\n", resolv.query("example.com"))'
{
"example.com": {
"A": [
"93.184.216.34"
],
"AAAA": [
"2606:2800:220:1:248:1893:25c8:1946"
]
}
}
Passing IP addresses will automatically perform PTR requests:
# ucode -mresolv -Rs 'printf("%.J\n", resolv.query("8.8.8.8"))'
{
"8.8.8.8.in-addr.arpa": {
"PTR": [
"dns.google"
]
}
}
# ucode -mresolv -Rs 'printf("%.J\n", resolv.query("2001:4860:4860::8888"))'
{
"8.8.8.8.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.6.8.4.0.6.8.4.1.0.0.2.ip6.arpa": {
"PTR": [
"dns.google"
]
}
}
Additional options for query type and nameserver selection can be passed via
a second optional options dictionary:
# ucode -mresolv -Rs 'printf("%.J\n",
resolv.query([ "openwrt.org", "example.org", "doesnotexist.tld" ], {
type: [ "A", "AAAA", "MX" ],
nameserver: [ "1.1.1.1", "8.8.4.4" ],
timeout: 5000,
retries: 2,
edns_maxsize: 4096
}))'
{
"openwrt.org": {
"A": [
"139.59.209.225"
],
"MX": [
[
10,
"util-01.infra.openwrt.org"
]
],
"AAAA": [
"2a03:b0c0:3:d0::1af1:1"
]
},
"example.org": {
"A": [
"93.184.216.34"
],
"AAAA": [
"2606:2800:220:1:248:1893:25c8:1946"
],
"MX": [
[
0,
"."
]
]
},
"doesnotexist.tld": {
"rcode": "NXDOMAIN"
}
}
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
When parsing the padding size specification of a `J` format, e.g. `%.4J`,
the internally called `atoi()` function might read beyond the end of the
initialized memory within the format buffer, leading to non-deterministic
results.
Avoid overreading the initialized memory by parsing the padding length
manually digit-by-digit.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
syntax: introduce optional chaining operators
|
|
Introduce new operators `?.`, `?.[…]` and `?.(…)` to simplify looking up
deeply nested property chain in a secure manner.
The `?.` operator behaves like the `.` property access operator but yields
`null` if the left hand side is `null` or not an object.
Like `?.`, the `?.[…]` operator behaves like the `[…]` computed property
access but yields `null` if the left hand side is `null` or neither an
object or array.
Finally the `?.(…)` operator behaves like the function call operator `(…)`
but yields `null` if the left hand side is `null` or not a callable
function.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Reset all callframes when dealing with an unhandled exception to avoid
resuming the code which raised the exception when restarting the VM
later, e.g. through uc_vm_call() or uc_vm_invoke().
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
If execution in an existing VM that threw an exception was resumed
through uc_vm_call() or uc_vm_invoke(), the exception was never cleared,
causing all subsequent calls to return with an exception status as well.
Ensure that any preexisting exception information is discarded before
executing the requested function in order to start from a clean state.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
lib: introduce Linux 802.11 netlink binding
|
|
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
When setting an array index which is beyond the end of the last currently
preallocated chunk and not evenly divisible by the chunk size, the array
entries list was not properly reallocated, resulting in invalid memory
writes.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
When compiling certain expressions as first statement of an ucode
program, e.g. a while loop in raw mode, a jump instruction to offset
zero is emitted which was incorrectly treated as placeholder by the
compiler.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
lib: introduce Linux route netlink binding
|
|
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
# ucode -mrtnl -Rs 'printf("%.J", rtnl.request(rtnl.const.RTM_GETROUTE, 0, { dst: "8.8.8.8" }))'
{
"family": 2,
"tos": 0,
"protocol": 0,
"scope": 0,
"type": 1,
"flags": 512,
"dst": "8.8.8.8/32",
"oif": "onboard",
"gateway": "10.11.12.13",
"prefsrc": "10.11.12.7",
"cacheinfo": {
"clntref": 2,
"lastuse": 0,
"expires": 0,
"error": 0,
"used": 0,
"id": 0,
"ts": 0,
"tsage": 0
},
"table": 254,
"uid": 0
}
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
# ucode -mrtnl -Rs 'printf("%.J", rtnl.request(rtnl.const.RTM_GETLINK, 0, { dev: "lo" }))'
{
"family": 0,
"type": 772,
"dev": "lo",
"flags": 65609,
"address": "00:00:00:00:00:00",
"broadcast": "00:00:00:00:00:00",
"txqlen": 1000,
"mtu": 65536,
"carrier": true,
"linkmode": 0,
"operstate": 0,
"num_tx_queues": 1,
"num_rx_queues": 1,
"af_spec": {
"inet": {
"conf": {
"forwarding": 1,
"mc_forwarding": 0,
"proxy_arp": 0,
"accept_redirects": 1,
"secure_redirects": 1,
"send_redirects": 1,
"shared_media": 1,
"rp_filter": 0,
"accept_source_route": 1,
"bootp_relay": 0,
"log_martians": 0,
"tag": 0,
"arpfilter": 0,
"medium_id": 0,
"noxfrm": 1,
"nopolicy": 1,
"force_igmp_version": 0,
"arp_announce": 0,
"arp_ignore": 0,
"promote_secondaries": 0,
"arp_accept": 0,
"arp_notify": 0,
"accept_local": 0,
"src_vmark": 0,
"proxy_arp_pvlan": 0,
"route_localnet": 0,
"igmpv2_unsolicited_report_interval": 10000,
"igmpv3_unsolicited_report_interval": 1000,
"ignore_routes_with_linkdown": 0,
"drop_unicast_in_l2_multicast": 0,
"drop_gratuitous_arp": 0,
"bc_forwarding": 0
}
},
"inet6": {
"mode": 0,
"flags": 2147483648,
"conf": {
"forwarding": 0,
"hoplimit": 64,
"mtu6": 65536,
"accept_ra": 1,
"accept_redirects": 1,
"autoconf": 1,
"dad_transmits": 1,
"rtr_solicits": -1,
"rtr_solicit_interval": 4000,
"rtr_solicit_delay": 1000,
"use_tempaddr": -1,
"temp_valid_lft": 604800,
"temp_prefered_lft": 86400,
"regen_max_retry": 3,
"max_desync_factor": 600,
"max_addresses": 16,
"force_mld_version": 0,
"accept_ra_defrtr": 1,
"accept_ra_pinfo": 1,
"accept_ra_rtr_pref": 1,
"rtr_probe_interval": 60000,
"accept_ra_rt_info_max_plen": 0,
"proxy_ndp": 0,
"optimistic_dad": 0,
"accept_source_route": 0,
"mc_forwarding": 0,
"disable_ipv6": 0,
"accept_dad": -1,
"force_tllao": 0,
"ndisc_notify": 0,
"mldv1_unsolicited_report_interval": 10000,
"mldv2_unsolicited_report_interval": 1000,
"suppress_frag_ndisc": 1,
"accept_ra_from_local": 0,
"use_optimistic": 0,
"accept_ra_mtu": 1,
"stable_secret": 0,
"use_oif_addrs_only": 0,
"accept_ra_min_hop_limit": 1,
"ignore_routes_with_linkdown": 0,
"drop_unicast_in_l2_multicast": 0,
"drop_unsolicited_na": 0,
"keep_addr_on_down": 0,
"rtr_solicit_max_interval": 3600000,
"seg6_enabled": 0,
"seg6_require_hmac": 0,
"enhanced_dad": 1,
"addr_gen_mode": 0,
"disable_policy": 0,
"accept_ra_rt_info_min_plen": 0,
"ndisc_tclass": 0,
"rpl_seg_enabled": 0
}
}
},
"proto_down": false,
"group": 0,
"ifname": "lo"
}
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Some netlink replies contain attributes with embeded payloads whose
length depends on the kernel version, e.g. IFLA_INET_CONF and
IFLA_INET6_CONF.
Deal with such cases by allowing the payloads to be shorter than
the expected size and by skipping struct members which would lead
to out-of-bounds accesses.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
In success case, always push the function return value onto the stack even
if no call frames are remaining after the function returned.
This is needed for host program code invoking ucode functions within a VM
context that already ran to completion.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Fixes: dfb7379 ("fs: implement chmod(), chown(), rename() and glob() functions")
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
The Fuzz test implementation so far is just boilerplate and fails due to
imposed memory limits on the CI runner.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|