LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   assembly cgi program printing garbage (https://www.linuxquestions.org/questions/programming-9/assembly-cgi-program-printing-garbage-4175609062/)

rblampain 07-03-2017 01:21 AM

assembly cgi program printing garbage
 
I have this old assembly program (nasm64) that does a good job of comparing strings in a particular way outside of CGI and I am trying to make it work as a CGI. It works correctly from the CLI but prints the typical square black boxes and question marks as a CGI (through a HTML/browser-document and Apache2), this string of garbage is always proportional to the length of the strings tested, so it is trying to print the string. In my test, ASCII strings are used but the program is intended to be used for true (non-ascii) utf-8 strings.

The same code in BASIC works perfectly (ascii tested again although the result should be the same with UTF-8 on a byte-by-byte comparison basis) but can't get the length given by CGI variable of the returned strings (how many bytes to read) and is too slow at string comparisons.
I have insufficient experience in C, Perl, PHP or Python etc and only a basic knowledge of Apache2 and this strings comparison is a real bottleneck in need of assembly code that I find is my fastest way of solving that sort of problems.

My questions are: What should I be looking for to solve the problem? Is Apache2 mis-configured/not-configured? I thought it was configured for UTF-8 by default and should automatically print through system call 1 (write) anything printable. Or could it be a GDM3 problem? Or a combination of both? Or do I miss something?

I assume the same code in C would give the same result so a solution for C would probably solve the problem in Assembly code.

Thank you for your help.

Unmodified Debian 7 and Apache2 from DVD installation.
New Gigabyte mobo AB350 with Feb 2017 BIOS.

NevemTeve 07-03-2017 02:15 AM

You forgot to attach the relevant code, also the problematic output.

Laserbeak 07-05-2017 03:08 AM

Are you printing the correct HTTP headers including Content-Type, Content-Length, etc.

If you're using UTF-8, you should send Content-Type: text/html; charset=utf-8 or Content-Type: text/plain; charset=utf-8

scasey 07-05-2017 04:53 PM

Apache is generally not configured for UTF-8 by default. Supplying the charset as Laserbeak mentioned would change it for that page.

You do understand that your CGI script needs to supply HTML output in order to be viewed in a browser. At a very minimum, it needs to send
Code:

Content-type: text/html
as the first thing...the blank line is significant. It should also send:
Code:

<html>
<head>
<meta charset="utf-8">
</head>
<body>
...
</body>
</html>

where ... represents the output of the CGI and whatever HTML formatting might be also required...although only the meta tag is required to address your question. Please let us know how that works for you.

And to repeat NevemTeve's question...may we see the code and the output, please?

rblampain 07-06-2017 12:36 AM

Thank you for the answers. My apologies, I was wrongly convinced it was so simple I did not think code was necessary, I also have to do this from the local library.
Code:

bits 64

global _start
section .text
_start:                                ; ELF entry point
;; print http header
;; =================
mov rax, 1                            ; sys_write
mov rdi, 1                            ; STDOUT
mov rsi, http_header              ; buffer
mov rdx, http_headerLen            ; length of buffer
syscall
;; print text
;; ==========
mov rax, 1                            ; sys_write
mov rdi, 1                            ; STDOUT
mov rsi, sometext                      ; buffer
mov rdx, sometextLen                ; length of buffer
syscall

mov rax, 60                            ; sys_exit
mov rdi, 0                            ; 0
syscall

section .data

sometext        :        db "Hello world!", 0Ah
sometextLen EQU $ - sometext

http_header: db        'Content-type: text/html', 0Ah, 0Ah
http_headerLen EQU $ - http_header

note: tried mov rdx, [sometextLen] - no good either

result through browser in asm
Code:

��H���W(�/�IQ�
result through CLI in asm
Code:

Content-type: text/html

Hello world!


Code:

#include "stdio.h"
 
int main(void) {
  printf( "Content-Type: text/html\n\n" );
  printf("Hello world !\n");
  return 0;
}

result through browser with C
Code:

��H���W(�/�IQP�
result through CLI with C
Code:

Content-Type: text/html

Hello world !

In nasm (version coming with Debian 7)
Code:

Content-Type: text/html; charset=utf-8
makes if freeze, I'll try to specify UTF-8 in the 'meta' line as suggested.

NevemTeve 07-06-2017 05:56 AM

How about sending 'HTTP/1.0 200 OK' first?

scasey 07-06-2017 08:57 AM

Quote:

Originally Posted by NevemTeve (Post 5731345)
How about sending 'HTTP/1.0 200 OK' first?

That comes from Apache in response to a request. It doesn't need to be programmed in the CGI program/script.

Guttorm 07-06-2017 09:42 AM

To me, it looks like Apache is simply outputting the binary instead of executing it.

https://httpd.apache.org/docs/2.4/howto/cgi.html

scasey 07-06-2017 12:13 PM

Quote:

Originally Posted by Guttorm (Post 5731435)
To me, it looks like Apache is simply outputting the binary instead of executing it.

https://httpd.apache.org/docs/2.4/howto/cgi.html

That's an excellent point!! I hadn't considered it because my CGI scripts are always plain text (perl) files, so when that happens to me it's very obvious.

rblampain, please show us how you are calling your program from the web page.

Edit: I just remembered why that happens. (tho I just saw that this is in the link Guttorm posted) The setting
Code:

AddHandler cgi-script .cgi .pl
in httpd.conf needs to include the suffix of the file to be executed, so if its .asm - add that to the AddHandler directive. Otherwise, apache doesn't know to execute the code, and just delivers it instead.

Laserbeak 07-06-2017 09:20 PM

That is probably the problem. But I wouldn't add .asm to CGI programs, just assemble it to a binary ending in .cgi.

scasey 07-06-2017 10:05 PM

Quote:

Originally Posted by Laserbeak (Post 5731728)
That is probably the problem. But I wouldn't add .asm to CGI programs, just assemble it to a binary ending in .cgi.

Good point. The OP probably already has a binary; it just needs to be renamed as something.cgi.

Sorry, I get caught up in the "root cause" and forget the simple solutions -- making the solution fit the conditions instead of 'tother way 'round...I also forget that some people might not have access to the httpd.conf

Laserbeak 07-07-2017 06:35 AM

Also, make sure it's in the right "cgi-bin" directory/folder.

Laserbeak 07-07-2017 11:39 AM

Quote:

Originally Posted by scasey (Post 5731106)
You do understand that your CGI script needs to supply HTML output in order to be viewed in a browser. At a very minimum, it needs to send

This is incorrect. If you send "Content-Type: text/plain" in the header, any browser will just display it as plain text. You do not have to send HTML.

Laserbeak 07-07-2017 01:19 PM

So this is only DOS/Windows compatible? I tried to assemble it and it wouldn't run. When I ran "file" on it, it said "COM executable for DOS".

scasey 07-07-2017 02:12 PM

Quote:

Originally Posted by Laserbeak (Post 5732002)
This is incorrect. If you send "Content-Type: text/plain" in the header, any browser will just display it as plain text. You do not have to send HTML.

Yes, that's true. Point is that the first thing from the script needs to be a "Content-Type:..." header followed by a blank line. If that's not present, the browser will report an error 500:
Code:

Server error!

The server encountered an internal error and was unable to complete your request.

Error message:
malformed header from script. Bad header=<html>: popup.pl

If you think this is a server error, please contact the webmaster.
Error 500

(this example is a script without the header so the first thing it sends is the <html> tag)

Laserbeak 07-07-2017 02:32 PM

Quote:

Originally Posted by scasey (Post 5732086)
Yes, that's true. Point is that the first thing from the script needs to be a "Content-Type:..." header

Yep! But you made it sound like you HAD to send text/html. Just pointing that out... no prob.

NevemTeve 07-07-2017 02:48 PM

> I tried to assemble it and it wouldn't run.
How did you try to assemble it? What command did you use?

Laserbeak 07-07-2017 04:41 PM

Quote:

Originally Posted by NevemTeve (Post 5732111)
> I tried to assemble it and it wouldn't run.
How did you try to assemble it? What command did you use?

Among others (including yasm)... this seemed most promising but it still didn't run:

Code:


nasm -f macho64 -o test.cgi cgi.asm

results:

Code:

| => nasm -f macho64 -o test.cgi cgi.asm
/* no output */
| => ./test.cgi
-bash: ./test.cgi: cannot execute binary file

| => file test.cgi
test.cgi: Mach-O 64-bit object x86_64

This is for Mac OS X:

Code:

| => uname -a
Darwin SpocksBrain 17.0.0 Darwin Kernel Version 17.0.0: Tue Jun 13 21:06:15 PDT 2017; root:xnu-4481.0.0.1.1~1/RELEASE_X86_64 x86_64


LOL I can almost run it this way, but it's in reverse order:

Code:

| => strings test.cgi
Hello world!
Content-type: text/html

The source code explicitly says "ELF entry point" but this is Mach-O. If I tried it on Solaris that uses ELF format binaries, it'd probably work fine.

Laserbeak 07-07-2017 05:19 PM

I compiled it in Solaris:

Code:

root@sunshine:~# uname -a
SunOS sunshine 5.11 11.3 i86pc i386 i86pc

Code:

root@sunshine:~# nasm -f elf64 -o test.cgi test.asm
Code:

root@sunshine:~# ./test.cgi
bash: ./test.cgi: Invalid argument

???

NevemTeve 07-07-2017 10:49 PM

I would try link it:
Code:

nasm -f elf64 -o test.o test.asm
ld -o test.cgi test.o


Laserbeak 07-07-2017 11:34 PM

Quote:

Originally Posted by NevemTeve (Post 5732261)
I would try link it:
Code:

nasm -f elf64 -o test.o test.asm
ld -o test.cgi test.o


This did work as far as I came up with an executable but it ran and didn't print anything out at all and I just returned to the prompt. Perhaps it went to some log somewhere?

It did not work for Mac OS X replacing -f elf64 with -f macho64 though

NevemTeve 07-08-2017 03:14 AM

Works for me:
Code:

uname -mr
3.16.0-4-amd64 x86_64
nasm -f elf64 -o rb_cgi.o rb_cgi.asm
ld -o rb_cgi.cgi rb_cgi.o
./rb_cgi.cgi

Content-type: text/html

Hello world!
file rb_cgi.*
rb_cgi.asm: ASCII text
rb_cgi.cgi: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, not stripped
rb_cgi.o:  ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped


rblampain 07-13-2017 12:17 AM

Quote:

How did you try to assemble it? What command did you use?
Code:

nasm -f elf64 test.asm  -o test.o
ld  test.o -o test
<form... action="cgi-bin/test">
<input type="submit" ..>

I did not try to add any extension in the linker command but in theory, the server does not need one. "document root" and "cgi-bin" directories have been left as per original default Debian 7 (no need for added "exec .extension" or "alias .." since whatever is in that directory is considered by Apache2 to be cgi executable)

This code does not call the server and also work in my case
Quote:

uname -mr
3.16.0-4-amd64 x86_64
nasm -f elf64 -o rb_cgi.o rb_cgi.asm
ld -o rb_cgi.cgi rb_cgi.o
./rb_cgi.cgi
Content-type: text/html
but the funny thing is that, calling the server through html submit, itdoes not work in C either even though gcc has no complaint about the source code, doing the same thing in "YABASIC" with two "print" statements in the code (one to screen and the other to file) does not print correctly to the screen (possibly not at all, I cannot remember) altough printing to file shows the correct output (6 'variable name=value' blocks), not code. So it apears that the garbage printed is not code but the correct output (always proportional to the string used) that for some reason Apache2 cannot render correctly. Since the browser is UTF-8 by default which YASM does not understand (although the data is temporarily ASCII only), perhaps, not printing to screen in YABASIC had to be expected so I did not worry too much about that.
I have used verbatim a more involved example from the NCSA (32bit) and it does not work either - same result.

NevemTeve 07-13-2017 02:37 AM

Works for me:
Code:

$ ls -l /usr/local/www/cgi-bin/rb_cgi
-rwxr-xr-x 1 projects devel 1096 Jul  8 10:11 /usr/local/www/cgi-bin/rb_cgi

$ file /usr/local/www/cgi-bin/rb_cgi
/usr/local/www/cgi-bin/rb_cgi: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, not stripped

$ wget -S -O cgiout http://127.0.0.1:/cgi-bin/rb_cgi
--2017-07-13 10:46:16--  http://127.0.0.1/cgi-bin/rb_cgi
Connecting to 127.0.0.1:80... connected.
HTTP request sent, awaiting response...
  HTTP/1.1 200 OK
  Date: Thu, 13 Jul 2017 08:46:16 GMT
  Server: Apache/2.4.18 (Unix) PHP/7.1.7 OpenSSL/1.0.2l
  Content-Length: 13
  Keep-Alive: timeout=15, max=100
  Connection: Keep-Alive
  Content-Type: text/html
Length: 13 [text/html]
Saving to: 'cgiout'

$ cat cgiout
Hello world!


scasey 07-13-2017 01:52 PM

Quote:

Originally Posted by rblampain (Post 5734272)
I did not try to add any extension in the linker command but in theory, the server does not need one. "document root" and "cgi-bin" directories have been left as per original default Debian 7 (no need for added "exec .extension" or "alias .." since whatever is in that directory is considered by Apache2 to be cgi executable)

I'm sorry, but that is not correct. The server does need an extension which matches one of the values in AddHandler in the httpd.conf file.
Without a matching extension, apache will not execute the script/program, but will just send the contents of the file, which in your case, is a binary file.

Please add a .cgi extension to your compiled file and try again. I don't believe it needs to be re-compiled with the extension, the file just has to have that name for apache to execute it instead of delivering it.

Laserbeak 07-13-2017 01:58 PM

I believe if it is in a designated cgi-bin directory the web server should try to execute the file and if that fails for some reason (anything from not being able to execute it at all to returning no header or a bad header) it should just give a server error. It shouldn't send the contents of the file, which means wherever the file was, it wasn't in a properly declared cgi-bin directory.

NevemTeve 07-13-2017 02:08 PM

As a last straw, one could check log-files access_log and error_log in directory /var/log/apache2

scasey 07-13-2017 05:39 PM

Quote:

Originally Posted by Laserbeak (Post 5734536)
I believe if it is in a designated cgi-bin directory the web server should try to execute the file and if that fails for some reason (anything from not being able to execute it at all to returning no header or a bad header) it should just give a server error. It shouldn't send the contents of the file, which means wherever the file was, it wasn't in a properly declared cgi-bin directory.

I stand corrected. It appears I've been very lazy and have just been applying the
Code:

Option ExecCGI
directive to directories containing executable scripts rather than creating ScriptAlias for them. When doing that, the
Code:

AddHandler cgi-script .cgi .pl
directive is also required.

When a ScriptAlias directive is defined for a folder, then neither of the other directives are required.

I believe I'll do some tweaking of the config file over the next couple of days. Thank you, Laserbeak and NevemTeve :hattip:

rblampain, what I've been saying will work, it's just not the only way, and probably not the best way. Please confirm that your cgi-bin does have a ScriptAlias defined for it. Something like:
Code:

ScriptAlias /cgi-bin/ /path/to/the/cgi-bin/
...and I would not expect that to be provided by default,because the realname directory needs to be specified. There may be a default example commented out:
Code:

# ScriptAlias: This controls which directories contain server scripts.
# ScriptAliases are essentially the same as Aliases, except that
# documents in the realname directory are treated as applications and
# run by the server when requested rather than as documents sent to the client.
# The same rules about trailing "/" apply to ScriptAlias directives as to
# Alias.
#
#ScriptAlias /cgi-bin/ "/var/www/cgi-bin"
#
# "/var/www/cgi-bin" should be changed to whatever your ScriptAliased
# CGI directory exists, if you have that configured.

(which I copied from my current httpd.conf -- which is why I need to use the other two directives :rolleyes:

rblampain 07-21-2017 12:42 AM

I cannot understand what the problem was. Initially having "charset=urf-8" (maybe not the exact spelling) in the header seemed to make it worse, so I took it out on the assumption that I only had ascci in the testing files. In my last test, I put that back and it works and I have no idea what the difference is. There was no need to alter any configuration, as explained in my previous post.


All times are GMT -5. The time now is 08:39 PM.