Page 1 of 2
easyfind-client (Mouette)
Posted: 08 Jan 2016, 08:01
by Gordon
Hi all.
I've been looking into Mouette's easyfind-client and while I like it a lot I also think there is a missed opportunity in it as well. What I found is that I cannot use it as is, because like the original software it depends on the key being accessible through the kernel cmdline. But my (sakaki) kernel overwrites the cmdline, meaning that this value is not there. I would also have liked it better if it had been a plug-in replacement for the old easyfind routines, but this client stores its data in a different file and a different format.
This can all be fixed and in fact I have already started rewriting the method to retrieve the key value, reading it directly from the onboard flash memory. Running as an individual application I've verified that this method returns the key on my B3 correctly. What I was wondering though is whether this same method will work on a B2 as well? Does the B2 use the same flash structure to load the key on the kernel command line? If so, would someone who owns a B2 be willing to compile and run this bit of code and see if it returns the key value. Of course this would work best if done by someone who has an alternative method to access this key value so he/she can compare the results.
Re: easyfind-client (Mouette)
Posted: 08 Jan 2016, 12:55
by wm.bubba
Hi Gordon,
I have a couple of B2's, and willing to give it a try.
I think I also know how to read the key directly. Just need to dig my old notes out.
Re: easyfind-client (Mouette)
Posted: 08 Jan 2016, 13:43
by MouettE
Gordon wrote:This can all be fixed and in fact I have already started rewriting the method to retrieve the key value, reading it directly from the onboard flash memory.
I eagerly wait for a pull request
Gordon wrote:What I was wondering though is whether this same method will work on a B2 as well? Does the B2 use the same flash structure to load the key on the kernel command line? If so, would someone who owns a B2 be willing to compile and run this bit of code and see if it returns the key value.
It should work on the B2 as well, the flash parameters are obviously different but the method is the same. I have a b2 for test purpose so I can also test your code.
Re: easyfind-client (Mouette)
Posted: 08 Jan 2016, 13:52
by Gordon
Perfect!
Code below. Nothing fancy. Just run gcc on it and execute the resulting a.out executable.
Code: Select all
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <mtd/mtd-user.h>
int main()
{
int fd = open("/dev/mtd1", O_RDWR);
int offset=0;
ssize_t buflen=3;
char buf[64];
char* key;
char* keyval;
while (buflen>0){
offset+=buflen;
if (buflen<64) offset++;
lseek(fd, offset, SEEK_SET);
read(fd, buf, sizeof(buf));
if (buflen==64 && strlen(buf)==0){
offset++;
lseek(fd, offset, SEEK_SET);
read(fd, buf, sizeof(buf));
}
buflen=strlen(buf);
key=strstr(buf,"key=");
if (key!=NULL && key==buf){
keyval = malloc(strlen(buf)-3);
strcpy(keyval, buf+4);
keyval[strlen(buf)-4] = '\0';
}
}
printf("%s\n",keyval);
return 0;
}
Re: easyfind-client (Mouette)
Posted: 08 Jan 2016, 15:25
by wm.bubba
Program compiled, and run:
Code: Select all
user@b2:~/temp/ef$ ll
total 20
drwxr-xr-x 2 user users 4096 Jan 8 20:21 .
drwxr-xr-x 6 user users 4096 Jan 8 20:14 ..
-rwxr-xr-x 1 user users 6473 Jan 8 20:21 a.out
-rw-r--r-- 1 user users 847 Jan 8 18:55 ef.c
user@b2:~/temp/ef$ ./a.out
user@b2:~/temp/ef$
but as you can see nothing is returned.
Re: easyfind-client (Mouette)
Posted: 08 Jan 2016, 16:10
by Gordon
Which means it doesn't work. Either because the u-boot environment is in a different partition than /dev/mtd1, or /dev/mtd1 is inaccessible, or "key" is named differently inside it. That is a bit of a disappointment, especially because I'm kind of running in the dark here in regards to the B2. But maybe someone else can figure out what needs to be changed to make this work on a B2?
Re: easyfind-client (Mouette)
Posted: 08 Jan 2016, 16:18
by MouettE
I will have a look and I'm pretty sure I'll find a working solution.
Re: easyfind-client (Mouette)
Posted: 08 Jan 2016, 17:45
by sakaki
Hi,
FWIW on our (rev 2 hardware) B2, running the current
Gentoo live-USB for B2, it is /dev/mtd0 defined in /etc/fw_env.config, thus:
Code: Select all
# MTD definition for Bubba|2
# MTD device name Device offset Env. size Flash sector size
/dev/mtd0 0x050000 0x002000 0x010000
/dev/mtd0 0x060000 0x002000 0x010000
Running Gordon's program (substituting of course /dev/mtd0, rather than /dev/mtd1) returns a blank line. However, I
can extract the key with:
Code: Select all
b2 mtdtest # strings /dev/mtd0 | grep -oP 'key=[^$]+'
key=dKMS<... omitted for privacy ...>CWp/6Eo=
(the same value is also returned by fw_printenv).
I haven't reflashed U-boot or changed the U-boot environment.
Hope that helps, sakaki
Re: easyfind-client (Mouette)
Posted: 09 Jan 2016, 11:45
by Gordon
Explanation of the code:
What it does is start at offset 3 (ignoring an integer value at offset 0 that I did not bother to investigate what it is for) and read data in chunks of a maximum of 64 bytes. How many bytes are returned depends on whether there is a \0 value within the 64 byte range. The cycle stops when the buffer starts with the 4 character sequence "key=" or when it hits two consecutive \0 characters (in which case the buffer length is 0 on the second read).
The problem here is that with the B2:
1. the u-boot environment is not in /dev/mtd1
2. is not at offset 3
So it might work if you change the line 'ssize_t buflen=3;' to read 'ssize_t buflen=50003;' (or 60003)
Edit: not true. Stopping the cycle the moment key was found was what was intended at first. It will in fact read the complete environment, i.e. to the point where it finds two consecutive '\0' characters.
Re: easyfind-client (Mouette)
Posted: 10 Jan 2016, 12:53
by sakaki
Made the suggested changes, but it still didn't work. I think the program below should do the trick however - it appears to print the key correctly on our B3s and (rev 2) B2, but YMMV (is there anyone out there with a rev 1 B2 who could try this out? paulchany?).
Compile with gcc and then run a.out (as root, to ensure you have read access to /dev/mtd{0,1}):
Code: Select all
/* Search for a U-boot variable in B2/B3's MTD memory and print it
By sakaki, 2016 - public domain - NO WARRANTY */
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
const char* PATTERN = "\0key=";
const int PATLEN = 5;
int main()
{
int fd;
off_t envlen = 0x010000;
off_t envstart = 0x000000;
char* data, *p, *end;
int f;
fd = open("/dev/mtd1", O_RDONLY);
if (fd == -1) {
/* looks like we are running on a B2 */
fd = open("/dev/mtd0", O_RDONLY);
envlen = 0x002000;
envstart = 0x060000;
}
if (fd == -1) return EXIT_FAILURE;
/* load whole file into memory, the U-boot env area is tiny */
lseek(fd, envstart, SEEK_SET);
data = malloc(envlen);
read(fd, data, envlen);
end=data+envlen;
for (f=0, p=data; f<PATLEN && p<end; p++)
f = (*p == PATTERN[f] ? f+1 : 0);
if (f == PATLEN) {
do write(STDOUT_FILENO, p, 1); while (++p<end && *p);
write(STDOUT_FILENO, "\n", 1);
} else write(STDOUT_FILENO, "FAILED\n", 7);
free(data);
close(fd);
return (f == PATLEN ? EXIT_SUCCESS : EXIT_FAILURE);
}
Best, sakaki
Re: easyfind-client (Mouette)
Posted: 10 Jan 2016, 17:29
by Gordon
Should it have been 0x60003 in stead of 60003? I suppose you did try that variation. Don't know why this would go wrong on the B2. In fact I found that if ithe code I posted did not catch the key it should have returned a segmentation fault on account of the printf command at the end trying to write an uninitialised value. Not returning anything at all should therefore never have happened.
While good to have something that appears to be working, I do dislike the part of needing to allocate 8k of memory for reading the u-boot env. The objective (at least from my part) is to use as little memory as possible. And of course integrate it with Mouette's code, replacing the current routine to read the key from cmdline.
Re: easyfind-client (Mouette)
Posted: 11 Jan 2016, 08:10
by sakaki
From running gdb on your code, what appears to be happening is this. Consider the lines:
followed by
and then ultimately
Code: Select all
offset+=buflen
if (buflen<64) offset++;
lseek(fd, offset, SEEK_SET);
in the case where an environment string with length > sizeof(buf) (64 bytes) is encountered (many of them are).
In such a situation, the value returned by strlen is essentially a random integer >=64. In my case it returns the value 70 (decimal) (depends what's on the stack after the last byte of buf, which is a bit of a lucky dip). What then happens is that the 70 gets added to offset, and as luck would have it, this causes it to seek past the (start of the) "key=..." string. The (indeterminate) value of keyval is then printed - this happens to be a pointer to zero memory on the B2 (at least with my compiler settings), so there is no segfault (running this on a PC (on a text file which is missing the target string) does segfault I agree, except with -O3 and similar, when it prints garbage).
Best, sakaki
Re: easyfind-client (Mouette)
Posted: 11 Jan 2016, 08:49
by Gordon
Good find.
It should be possible to fix this by using:
And hardcode the value 64 where sizeof(buf) was used
Funny that I did not hit the issue with random characters following the read buffer on the B3. And I'm certain about that, because I had some additional print lines in there at first, dumping the complete environment to screen.
BTW I found what the first four bytes in the environment are for. It's a CRC32 checksum.
Re: easyfind-client (Mouette)
Posted: 11 Jan 2016, 09:28
by wm.bubba
Making the changes outlined (see code below), returns the correct key on both my B2's.
Code: Select all
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <mtd/mtd-user.h>
int main()
{
int fd = open("/dev/mtd0", O_RDWR);
int offset=0;
ssize_t buflen=0x60003;
char buf[65];
buf[64]='\0';
char* key;
char* keyval;
while (buflen>0){
offset+=buflen;
if (buflen<64) offset++;
lseek(fd, offset, SEEK_SET);
read(fd, buf, 64);
if (buflen==64 && strlen(buf)==0){
offset++;
lseek(fd, offset, SEEK_SET);
read(fd, buf, 64);
}
buflen=strlen(buf);
key=strstr(buf,"key=");
if (key!=NULL && key==buf){
keyval = malloc(strlen(buf)-3);
strcpy(keyval, buf+4);
keyval[strlen(buf)-4] = '\0';
}
}
printf("%s\n",keyval);
return 0;
}
Re: easyfind-client (Mouette)
Posted: 11 Jan 2016, 10:39
by Gordon
Aha. Progress.
So then this should work for both platforms:
Code: Select all
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <mtd/mtd-user.h>
char* getkey() {
#if defined(__powerpc__) || defined(__ppc__) || defined(__PPC__)
int fd = open("/dev/mtd0", O_RDWR);
int offset=0x60000;
#else
int fd = open("/dev/mtd1", O_RDWR);
int offset=0;
#endif
ssize_t buflen=3;
char buf[65];
char* key;
char* keyval="";
buf[64]='\0';
while (buflen>0 && offset<0x20000){
offset+=buflen;
if (buflen<64) offset++;
lseek(fd, offset, SEEK_SET);
read(fd, buf, 64);
if (buflen==64 && strlen(buf)==0){
offset++;
lseek(fd, offset, SEEK_SET);
read(fd, buf, 64);
}
buflen=strlen(buf);
key=strstr(buf,"key=");
if (key!=NULL && key==buf){
keyval = malloc(strlen(buf)-3);
strcpy(keyval, buf+4);
keyval[strlen(buf)-4] = '\0';
}
}
return keyval;
}
int main() {
printf("%s\n",getkey());
}
(and be a drop in replacement for the current procedure that reads the key from cmdline)