Hi seL4-devs and users,
I have a question about implementing server and client using badged
endpoints. Below I have laid out the scenario, the issue, and some
questions.
*Scenario*
I have a userspace server that implements the functionality for an
object(say type obj_T1). The server hands out badged-endpoints to clients
to interact with this object. The badge is the virtual address of the
object's struct in the server’s virtual address space. A client can
interact with the object by sending messages on this badged endpoint. The
client never learns the badge value. The kernel extracts the badged value
when the server receives a message on this endpoint. By using the badge
value, the server knows which object the client is trying to manipulate.
The same PD, which implements the 1st server, also implements another
server(in a separate thread, but same address space) for another object
type (say type obj_T2). The server follows the same paradigm of handing out
badged endpoints and using the badges values to keep track of the object.
*Issue*
I have a scenario where the client wants to invoke the functionality of
obj_T1. This functionality needs access to obj_T2 as well. The client has
badged EP caps to both objects. The client can invoke the badged EP handed
out by server-1 for obj_T1 and give the badged EP of obj_T2 as an extraCap
in the IPC message(or vice versa). Since the server has no way to look up
the badge of the second cap, it cannot look up the underlying object for
obj_T2.
So my questions are:
1.
Is there a way for a PD to look up the badge value of badged EP? I think
the answer is no, but I thought I would still ask.
2.
Is my idea of using the badge to keep track of the underlying object on
the right track? Is there a better way of going about doing it?
3.
As a potential solution, I can extend my server to add a new function,
say GETID, which returns the badge value of a given object(i.e., EP). Since
I know that the server always badges the EP with the virtual address of the
struct, it is a trivial call to implement. But I somehow feel like this is
not a neat idea, not quite sure why.
Thanks for the help, everyone!
Sid
CS Graduate Student @ UBC
sid-agrawal.ca
It is our pleasure to confirm that the seL4 Summit 2022 will be in:
Munich, Germany in the week of Oct 10th, 2022
It will be hosted by seL4 Foundation member Hensoldt Cyber. It will be a hybrid in-person/online event (if you'd like to propose a talk to be delivered remotely, please notify it in the submission).
Remember that you have until Monday 9th of May 2022 to propose a talk.
https://sel4.systems/news/2022https://sel4.systems/Foundation/Summit/https://sel4.systems/Foundation/Summit/cfp
Hello seL4 devs and users,
I am trying to send two capabilities from one process to another via the
extraCaps mechanism in the IPC. I can get it working when I send just 1
cap, but when I am sending 2 caps, the 2nd one never makes it. The
extraCaps field on the receiver side is somehow always 1. Looking at the
seL4 manual, I understood that I could send more than 1 capability via an
IPC. But since on the receiver side, I can only specify one receive slot, I
assumed that if more than 1 capability is received, it will be put in the
consecutive slots. Not sure if this is a valid assumption.
Looking at kerne/libsel4/include/sel4/constants.h
<https://github.com/seL4/seL4/blob/master/libsel4/include/sel4/constants.h#L…>,
I see that seL4_MsgMaxExtraCaps is set to 2, so I think I should be able to
send 2 caps. I have spent about 3 days trying to make this work and thought
that at this stage, it would be best to ask :)
My C code on the sender side looks something like this:
seL4_CPtr cap1 = <alloc some capability>
seL4_CPtr cap2 = <alloc some capability>
seL4_SetMR(0, 0xabcd);
seL4_SetCap(0, cap1);
seL4_SetCap(1, cap2);
seL4_MessageInfo_t tag = seL4_MessageInfo_new(0, 0, 2, 1);
tag = seL4_Call(receivers_ep_cap, tag);
On the receive side, the code looks something like this:
/* Allocate one csapce slot */
cspacepath_t received_cap_path_1;
error = vka_cspace_alloc_path(simple-vka, &received_cap_path_1); <-
slot = 2786
assert(error == 0);
/* Allocate another csapce slot */
cspacepath_t received_cap_path_2;
error = vka_cspace_alloc_path(simple-vka, &received_cap_path_2); <-
slot = 2785(somehow decreasing)
assert(error == 0);
/* Since the allocated slots are decreasing in count, I pick the
lesser one as my first slot
* assuming that if more than 1 cap is received it will be put in
the next slot */
seL4_CPtr min_cptr = MIN(received_cap_path_1.capPtr,
received_cap_path_2.capPtr);
seL4_SetCapReceivePath(
/* _service */ received_cap_path.root,
/* index */ min_cptr,
/* depth */ received_cap_path.capDepth);
tag = recv(&sender_badge);
assert(seL4_MessageInfo_get_extraCaps(tag) == 2); <--- This asser
fails.
Thanks again!!
Sid
Graduate Student @ UBC
The kernel supports attaching a capability to an RTReply xfer.
sel4test even checks this WAI. But capdl doesn't seem to support it as I
see no way to express the set of rights associated with a capability to an
RTReply object. I added capdl support so I can mark the Grant right and
verified cap xfer works. TWas this intentional?
-Sam
Hi,
I tried to build vm_multi for qemu-arm-virt using the procedures in this link https://docs.sel4.systems/projects/camkes-vm/. After building, I used the generated simulation file to do ./simulate in my build directory. After displaying 'welcome to buildroot', the console always prints the log "udhcpc: sending discover",which indicates udhcpc can not return.
The related log was shown below:
Starting syslogd: OK
Starting syslogd: OK
Starting syslogd: OK
Starting klogd: OK
Starting klogd: OK
Starting klogd: OK
Running sysctl: OK
Running sysctl: OK
Running sysctl: OK
Initializing random number generator... [ 7.195263] random: dd: uninitialized urandom read (512 bytes read)
done.
Initializing random number generator... [ 7.315113] random: dd: uninitialized urandom read (512 bytes read)
done.
Initializing random number generator... [ 7.300770] random: dd: uninitialized urandom read (512 bytes read)
done.
Starting network: OK
Starting network: OK
Starting network: OK
udhcpc: started, v1.31.0
udhcpc: started, v1.31.0
ifconfig: SIOCGIFFLAGS: No such device
[ 9.077855] random: mktemp: uninitialized urandom read (6 bytes read)
[ 9.177878] random: mktemp: uninitialized urandom read (6 bytes read)
Welcome to Buildroot
udhcpc: sending discover
udhcpc: sending discover
udhcpc: sending discover
udhcpc: sending discover
As the simulation process progresses there was an error:
_utspace_split_alloc@split.c:266 Failed to find any untyped capable of creating an object at address 0x10080000
alloc_vm_device_cap@main.c:938 Grabbing the entire cap for device memory
alloc_vm_device_cap@main.c:941 Failed to grab the entire cap
My question is:
1. Is the two things have dependencies (The error and the hang at booting the system up)?
2. How can this issue be solved?
3. Is this issue related to the TimeServer component being imported to Qemu (as this is indicated as a requirement to run multi_vm on qemu-arm-virt)?
Thank you for your time
hello devel,
Why vppi , such as vtimer interrupt to guest, is sent from kernel to vmm by fault endpoint but not by notification?
I see that spi to guest is sent from kernel to vmm by notification.
thank you.
Hi all
A friendly reminder that the seL4 developer hangout is on again this week:
Tue, Apr 19, 10pm (UTC)
* Sydney: Wed, Apr 20, 8am
* Central Europe: Wed, Apr 20, 12 midnight
* US Pacific Time: Tue, Apr 19, 3pm
Zoom link: https://unsw.zoom.us/j/82640784431
Cheers,
Gerwin
Thanks Peter!
In my experience posts like that, linking to pornographic websites, are not made by humans anyway, but rather by bots. I don’t think this will effect humans too much except at the very beginning.
It may make sense to implement a different captcha, as often the developers of those bots can outsource solving common captcha providers to underpaid humans. Using an uncommon or home-grown captcha solution will make it less likely that bots will be able to get around them using that method. And attacks like these aren’t targeted, usually, so I doubt the bot writers will adapt for one specific mailing list. That will stop bots from signing up in the first place, hopefully.
We could also maybe report abuse of free email services like Gmail or Hotmail or similar in a semi-automated fashion. Would not surprise me if there is some sort of API for that. But on the other hand with the way those companies work it could be a waste of time and effort, since they might not do anything.
And it may also make sense to keep track of which domains non-malicious users are sending email from. That way we can ban entire domains without worrying about getting rid of legitimate users unintentionally.
For example, a small webmail service that we may not realize is a public email service at first, could be used by both a malicious user and a legitimate one. That way we’re only banning domains controlled by spammers exclusively.
There’s lots of resources for this stuff thankfully, you can go on a whole tangent reading about email spam prevention on Wikipedia.
I wish you luck with figuring out how to stop this annoying nonsense.
I'm trying to setup a development machine for seL4 work. I would like to use v12.1.0. I setup seL4test-manifest per instructions here https://docs.sel4.systems/Hardware/spike.html
repo init -u https://github.com/seL4/sel4test-manifest.git
repo sync
mkdir cbuild
cd cbuild
../init-build.sh -DPLATFORM=spike -DRISCV64=1
# The default cmake wrapper sets up a default configuration for the target platform.
# To change individual settings, run `ccmake` and change the configuration
# parameters to suit your needs.
ninja
# If your target binaries can be executed in an emulator/simulator, and if
# our build system happens to support that target emulator, then this script
# might work for you:
./simulate
I used repo init -u https://github.com/seL4/sel4test-manifest.git -b refs/tags/12.1.0 to be sure I got 12.1.0 but it doesn't matter, both branches/tags give the same error when I configure/compile.
$ ../init-build.sh -DPLATFORM=spike -DRISCV64=1 -DSIMULATION=1
loading initial cache file /mnt/data/sel4test/projects/sel4test/settings.cmake
-- Set platform details from PLATFORM=spike
-- KernelPlatform: spike
-- Setting from flags KernelSel4Arch: riscv64
-- Found seL4: /mnt/data/sel4test/kernel
-- Found GCC with prefix riscv64-unknown-linux-gnu-
-- Found GCC with prefix riscv64-unknown-linux-gnu-
-- The C compiler identification is GNU 10.2.0
-- The CXX compiler identification is GNU 10.2.0
-- The ASM compiler identification is GNU
-- Found assembler: /mnt/data/opt/riscv/bin/riscv64-unknown-linux-gnu-gcc
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /mnt/data/opt/riscv/bin/riscv64-unknown-linux-gnu-gcc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /mnt/data/opt/riscv/bin/riscv64-unknown-linux-gnu-g++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Found elfloader-tool: /mnt/data/sel4test/tools/seL4/elfloader-tool
-- /mnt/data/sel4test/build/kernel/gen_headers/plat/machine/devices_gen.h is out of date. Regenerating...
-- CPIO test cpio_reproducible_flag PASSED
-- Found musllibc: /mnt/data/sel4test/projects/musllibc
-- Found util_libs: /mnt/data/sel4test/projects/util_libs
-- Found seL4_libs: /mnt/data/sel4test/projects/seL4_libs
-- Found sel4_projects_libs: /mnt/data/sel4test/projects/sel4_projects_libs
-- Found sel4runtime: /mnt/data/sel4test/projects/sel4runtime
-- Performing Test compiler_arch_test
-- Performing Test compiler_arch_test - Success
-- libmuslc architecture: 'riscv' (from KernelSel4Arch 'riscv64')
-- Detecting cached version of: musllibc
-- Found Git: /usr/bin/git (found version "2.25.1")
-- Not found cache entry for musllibc - will build from source
-- Found PythonInterp: /usr/bin/python (found version "2.7.18")
CMake Warning (dev) at /home/user/.local/lib/python3.8/site-packages/cmake/data/share/cmake-3.22/Modules/FindPackageHandleStandardArgs.cmake:438 (message):
The package name passed to `find_package_handle_standard_args` (NANOPB)
does not match the name of the calling package (Nanopb). This can lead to
problems in calling code that expects `find_package` result variables
(e.g., `_FOUND`) to follow a certain pattern.
Call Stack (most recent call first):
/mnt/data/sel4test/tools/nanopb/extra/FindNanopb.cmake:340 (FIND_PACKAGE_HANDLE_STANDARD_ARGS)
/mnt/data/sel4test/tools/seL4/cmake-tool/helpers/nanopb.cmake:29 (find_package)
/mnt/data/sel4test/projects/sel4_projects_libs/libsel4nanopb/CMakeLists.txt:11 (include)
This warning is for project developers. Use -Wno-dev to suppress it.
-- Found NANOPB: /mnt/data/sel4test/tools/nanopb
-- Configuring done
-- Generating done
-- Build files have been written to: /mnt/data/sel4test/build
user@user-KVM:/mnt/data/sel4test/build$ ninja
[42/267] Building ASM object kernel/CMakeFiles/kernel.elf.dir/src/arch/riscv/head.S.obj
FAILED: kernel/CMakeFiles/kernel.elf.dir/src/arch/riscv/head.S.obj
/usr/bin/ccache /mnt/data/opt/riscv/bin/riscv64-unknown-linux-gnu-gcc --sysroot=/mnt/data/sel4test/build -I/mnt/data/sel4test/kernel/include/plat/default -I/mnt/data/sel4test/kernel/include -I/mnt/data/sel4test/kernel/include/64 -I/mnt/data/sel4test/kernel/include/arch/riscv -I/mnt/data/sel4test/kernel/include/arch/riscv/arch/64 -I/mnt/data/sel4test/kernel/include/plat/spike -I/mnt/data/sel4test/kernel/include/plat/spike/plat/64 -I/mnt/data/sel4test/kernel/libsel4/include -I/mnt/data/sel4test/kernel/libsel4/arch_include/riscv -I/mnt/data/sel4test/kernel/libsel4/sel4_arch_include/riscv64 -I/mnt/data/sel4test/kernel/libsel4/sel4_plat_include/spike -I/mnt/data/sel4test/kernel/libsel4/mode_include/64 -I/mnt/data/sel4test/build/kernel/gen_config -I/mnt/data/sel4test/build/kernel/autoconf -I/mnt/data/sel4test/build/kernel/gen_headers -I/mnt/data/sel4test/build/kernel/generated -march=rv64imac -mabi=lp64 -D__KERNEL_64__ -O2 -g -DNDEBUG -nostdinc -nostdlib -O2 -DHAVE_AUTOCONF -DDEBUG -g -ggdb -mcmodel=medany -fno-pic -fno-pie -fno-stack-protector -fno-asynchronous-unwind-tables -std=c99 -Wall -Werror -Wstrict-prototypes -Wmissing-prototypes -Wnested-externs -Wmissing-declarations -Wundef -Wpointer-arith -Wno-nonnull -ffreestanding -MD -MT kernel/CMakeFiles/kernel.elf.dir/src/arch/riscv/head.S.obj -MF kernel/CMakeFiles/kernel.elf.dir/src/arch/riscv/head.S.obj.d -o kernel/CMakeFiles/kernel.elf.dir/src/arch/riscv/head.S.obj -c /mnt/data/sel4test/kernel/src/arch/riscv/head.S
/mnt/data/sel4test/kernel/src/arch/riscv/head.S: Assembler messages:
/mnt/data/sel4test/kernel/src/arch/riscv/head.S:24: Error: unrecognized opcode `fence.i'
/mnt/data/sel4test/kernel/src/arch/riscv/head.S:31: Error: unrecognized opcode `csrw sscratch,x0'
[44/267] Invoking muslc build system
/mnt/data/sel4test/projects/musllibc/src/unistd/getcwd.c: In function 'getcwd':
cc1: warning: function may return address of local variable [-Wreturn-local-addr]
/mnt/data/sel4test/projects/musllibc/src/unistd/getcwd.c:9:7: note: declared here
9 | char tmp[PATH_MAX];
| ^~~
ninja: build stopped: subcommand failed.
I tried riscv-gcc 10.2.0 and 11.1.0 with the same results.
$ riscv64-unknown-linux-gnu-gcc --version
riscv64-unknown-linux-gnu-gcc (gca312387ab1) 10.2.0
Copyright (C) 2020 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Is there some extension I need to add to get this working? Where do I do that?
Hi
The root cause of this problem has been found, when Guest OS do the virtio console driver probe,
if virtqueue's desc addr allocated by alloc_pages_exact() in the setup_vq() function is >= 0x100000000
(it is common when the memory of VM allocated exceeds 3G), at first It will be shifted right
12 bits by Guest OS(turn into a value >= 0x100000), and then use iowrite32(iobase + VIRTIO_PCI_QUEUE_PFN) to notify Host,
after unsigned int type data be shifted left 12 bits by Host, the higest bits 0x1 of virtqueue's desc addr will be lost.
I have submitted a PR for the amendment, waiting for the review and merge into the main branch.
https://github.com/seL4/seL4_projects_libs/pull/43
BR.
Allen
发件人: Han JingLong 韩景龙
发送时间: 2022年3月21日 20:27
收件人: 'devel(a)sel4.systems' <devel(a)sel4.systems>
主题: Report "Failed to touch ram region" error using virtio_console when assigned for Arm-VM more than 3G memory
Hi
I had make virtio_console work well on my environment(armv8, RAM is 8G) based on vm_multi with Linux Guest OS(512M) and Android Guest OS(<= 3G)
But I meet an error(vm_ram_touch@guest_ram.c:157<mailto:vm_ram_touch@guest_ram.c:157> Failed to touch ram region: Not registered RAM region)
when assign for a VM(Android Guest OS) more than 3G memory.
1. Some logs are added for debugging this issue:
+++ b/seL4_projects_libs/libsel4vmmplatsupport/src/drivers/virtio_emul.c
@@ -86,6 +86,7 @@ static int emul_io_out(virtio_emul_t *emul, unsigned int offset, unsigned int si
assert(size == 4);
int queue = emul->virtq.queue;
emul->virtq.queue_pfn[queue] = value;
+ printf("[hjl] queue_size:%d desc:%p\n", emul->virtq.queue_size[queue], (void *)(uintptr_t)(value << 12));
vring_init(&emul->virtq.vring[queue], emul->virtq.queue_size[queue], (void *)(uintptr_t)(value << 12),
VIRTIO_PCI_VRING_ALIGN);
break;
+++ b/seL4_projects_libs/libsel4vmmplatsupport/src/drivers/virtio_emul_helpers.c
@@ -25,10 +25,43 @@ static int write_guest_mem(vm_t *vm, uintptr_t phys, void *vaddr, size_t size, s
int vm_guest_write_mem(vm_t *vm, void *data, uintptr_t address, size_t size)
{
+ bool is_inram = false;
+ vm_mem_t *guest_memory = &vm->mem;
+ for (int i = 0; i < guest_memory->num_ram_regions; i++) {
+ if (guest_memory->ram_regions[i].start <= address &&
+ guest_memory->ram_regions[i].start + guest_memory->ram_regions[i].size >= address + size) {
+ /* We are within a ram region*/
+ is_inram = true;
+ }
+ }
+
+ if (!is_inram) {
+ printf("[hjl] write mem addr:%p size:0x%lx\n", address, size);
+ for (int index = 0; index < guest_memory->num_ram_regions; index++) {
+ printf("[hjl] write mem ram_regions start:%p size:0x%lx\n", guest_memory->ram_regions[index].start, guest_memory->ram_regions[index].size);
+ }
+ }
+
return vm_ram_touch(vm, address, size, write_guest_mem, data);
}
int vm_guest_read_mem(vm_t *vm, void *data, uintptr_t address, size_t size)
{
+ bool is_inram = false;
+ vm_mem_t *guest_memory = &vm->mem;
+ for (int i = 0; i < guest_memory->num_ram_regions; i++) {
+ if (guest_memory->ram_regions[i].start <= address &&
+ guest_memory->ram_regions[i].start + guest_memory->ram_regions[i].size >= address + size) {
+ /* We are within a ram region*/
+ is_inram = true;
+ }
+ }
+
+ if (!is_inram) {
+ printf("[hjl] read mem addr:%p size:0x%lx\n", address, size);
+ for (int index = 0; index < guest_memory->num_ram_regions; index++) {
+ printf("[hjl] read mem ram_regions start:%p size:0x%lx\n", guest_memory->ram_regions[index].start, guest_memory->ram_regions[index].size);
+ }
+ }
return vm_ram_touch(vm, address, size, read_guest_mem, data);
}
2. The detailed log is as follows:
[hjl] queue_size:128 desc:0x8eb6000
[hjl] queue_size:128 desc:0x8eb8000
[hjl] read mem addr:0x8eb8802 size:0x2
[hjl] read mem ram_regions start:0x80000000 size:0x80000
[hjl] read mem ram_regions start:0x80080000 size:0x17cda00
[hjl] read mem ram_regions start:0x8184da00 size:0xa5b2600
[hjl] read mem ram_regions start:0x8be00000 size:0x83ae98
[hjl] read mem ram_regions start:0x8c63ae98 size:0x29c5168
[hjl] read mem ram_regions start:0x8f000000 size:0x26d35
[hjl] read mem ram_regions start:0x8f026d35 size:0xc0fd92cb
vm_ram_touch@guest_ram.c:157<mailto:vm_ram_touch@guest_ram.c:157> Failed to touch ram region: Not registered RAM region
3. devices.camkes configuration reference is as follows:
#define VM1_RAM_BASE 0x80000000
#define VM1_RAM_SIZE 0xD0000000
#define VM1_DTB_ADDR 0x8F000000 //VM1_RAM_BASE + 0xF000000
#define VM1_INITRD_ADDR 0x8BE00000 //VM1_DTB_ADDR - VM1_INITRD_MAX_SIZE
vm1.untyped_mmios = [
"0x80000000:28", // RAM
"0x90000000:28", // RAM
"0xa0000000:28", // RAM
"0xb0000000:28", // RAM
"0xc0000000:28", // RAM
"0xd0000000:28", // RAM
"0xe0000000:28", // RAM
"0xf0000000:28", // RAM
"0x100000000:28", // RAM
"0x110000000:28", // RAM
"0x120000000:28", // RAM
"0x130000000:28", // RAM
"0x140000000:28", // RAM
/*
"0x150000000:28", // RAM
"0x160000000:28", // RAM
"0x170000000:28", // RAM
"0x180000000:28", // RAM
"0x190000000:28", // RAM
"0x1a0000000:28", // RAM
"0x1b0000000:28", // RAM
*/
];
4. Present situation:
At present, I tracked and found that When the Guest OS's virtio_console driver do the probe,
it created the vring and iowrite to notify VMM of the virtqueue desc 's physical address in setup_vq()
/* create the vring */
static void *vring_alloc_queue(struct virtio_device *vdev, size_t size,
dma_addr_t *dma_handle, gfp_t flag)
{
......
void *queue = alloc_pages_exact(PAGE_ALIGN(size), flag);
if (queue) {
phys_addr_t phys_addr = virt_to_phys(queue);
*dma_handle = (dma_addr_t)phys_addr;
/* activate the queue */
iowrite32(virtqueue_get_desc_addr(vq) >> VIRTIO_PCI_QUEUE_ADDR_SHIFT,
vp_dev->ioaddr + VIRTIO_PCI_QUEUE_PFN);
I'm very confused why is the physical memory allocated for virtqueue desc not within
the effective memory range of VM when assign the memory to it exceeds 3G?
BR.
Allen
邮件免责申明
Email Disclaimer
本邮件仅供本邮件指定收件人使用,其所载内容可能因含有保密信息或其它原因而不得披露。除本公司及本邮件指定收件人外,任何人不得公开、传播、分发、复制、印刷或使用本邮件之任何部分或其所载之任何内容。如您误收到本邮件,请立即通知本公司,并将原始邮件、附件及其所有复本从系统中删除,切勿使用。
This email is for the use of the designated receivers only,and the content is not allowed to be disclosed due to the confidential information or other reasons. Except for the Company and the designated receivers of this email, no one shall disclose, disseminate, distribute, copy, print or use any part of this email or any content contained therein. If you receive this email by mistake, please notify the Company immediately, and delete the original email, attachments and all copies from the system. Do not use it.
网络通信可能含有计算机病毒或其它缺陷,可能无法准确和/或及时送达其它系统,亦可能受阻而不为本公司或本邮件指定收件人所知。本公司对此类错误或遗漏以及任何因使用本邮件而引致之任何损失概不承担责任。
Network communication may contain computer viruses or other defects, which may not be delivered to other systems accurately and / or in time, or may be blocked by the Company or the designated receivers of this email. The Company shall not be liable for such errors or omissions and for any loss arising from this email.
本邮件所载任何内容仅作为业务层面交流与参考,除非明确说明,本公司不对邮件所载内容之准确性、完整性或公平性等承担任何法律责任。
Any contents contained in this email are only for the purpose of business communication and reference only. Unless explicitly stated otherwise, the Company shall not assume any legal responsibility for the accuracy, completeness or fairness of the content contained in the email.
本邮件指定收件人应特别注意:本邮件所载任何内容不构成本公司对本邮件指定收件人和/或其所属商业实体的任何要约、要约邀请或承诺,任何权利义务皆以双方签字盖章的书面文件为准。除经本公司以签字盖章的书面文件确认外,收件人和/或其所属商业实体不得以本邮件所载任何内容作为其向本公司主张任何权利或利益的正式依据。
The designated receivers should pay special attention to the fact that nothing contained in this email shall constitute an offer, invitation or acceptance by the Company to the designated receivers of this email and/or its affiliated business entities, and any rights and obligations are subject to the written documents signed and sealed by both parties. Except from the written document signed ,sealed and confirmed by the Company, the receivers and / or its affiliated business entity shall not rely on anything contained in this email as the formal basis for claiming any rights or interests to the Company.