The bug would be closed as invalid.
No matter what you consider as being better, changing a 12 years old and
widely used userspace interface like /dev/urandom is simply not an
cu
Adrian
--
"Is there not promise of rain?" Ling Tan asked suddenly out
of the darkness. There had been need of rain for many days.
"Only a promise," Lao Er said.
Pearl S. Buck - Dragon Seed
--
Fixing it to be more efficient in its use of entropy and also fixing the fact its not actually a good random number source would be worth looking at however. --
Yes, since current behavior on network irq is very pessimistic. If you have some trafic, (ie more than HZ/2 interrupts per second),=20 then add_timer_randomness() feeds some entropy but gives no credit (calling credit_entropy_store() with=20 nbits=3D0) This is because we take into account only the jiffies difference, and=20 not the get_cycles() that should give us more entropy on most plaforms. In this patch, I suggest that we feed only one u32 word of entropy,=20 combination of the previous distinct words (with some of them being constant or so), so that the nbits=20 estimation is less pessimistic, but also to avoid injecting false entropy. Signed-off-by: Eric Dumazet <dada1@cosmosbay.com>
No, it's very optimistic. The network should not be trusted. The distinction between /dev/random and /dev/urandom boils down to one word: paranoia. If you are not paranoid enough to mistrust your network, then /dev/random IS NOT FOR YOU. Use /dev/urandom. Do not If we cannot measure a difference, we should nonetheless assume there Umm.. no, that's not how it works at all. Also, for future reference, patches for /dev/random go through me, not through Dave. -- Mathematics is the supreme nostalgia of our time. --
You keep saying that. I am refering to your previous attempts last year to remove net drivers from sources of entropy. No real changes were done. If the network should not be trusted, then a patch should make sure network interrupts feed /dev/urandom but not /dev/random at all. (ie not calling I have many tg3 adapters on my servers, receiving thousand of interrupts per second, and calling add_timer_randomness(). I would like to either : - Make sure this stuff is doing usefull job. - Make improvements to reduce cpu time used. I do not use /dev/urandom or/and /dev/random, but I know David wont accept a patch to remove IRQF_SAMPLE_RANDOM from tg3.c Currently, I see that current implementation is suboptimal because it calls There is a big difference on get_cycles() and jiffies. You should try to Why ? David is the network maintainer, and he was the one who rejected your previous patches. --
Dave and I are both a bit stubborn on this point. I've been meaning to Yes. My plan is to change the interface from SA_SAMPLE_RANDOM to add_network_entropy. The SA_SAMPLE_RANDOM interface sucks because it I'm well aware of that. We'd use get_cycles() exclusively, but it returns zero on lots of platforms. We used to use sched_clock(), I Because I'm the /dev/random maintainer and it's considered the polite thing to do, damnit. -- Mathematics is the supreme nostalgia of our time. --
Not true, as I've already pointed out in this thread. -- Mathematics is the supreme nostalgia of our time. --
/dev/urandom always leaves enough entropy in the input pool for /dev/random to reseed. Thus, as long as entropy is coming in, it is not possible for /dev/urandom readers to starve /dev/random readers. But /dev/random readers may still block temporarily and they should damn well expect to block if they read 500 bytes out of a 512 byte pool. -- Mathematics is the supreme nostalgia of our time. --
A paranoid application should only need to read ~500 bytes if it is
generating a long-term RSA private key, and in that case, it would do
well to use a non-blocking read, and if it can't get enough bytes, it
should prompt the user to move the mouse around or bang on the
keyboard. /dev/random is *not* magic where you can assume that you
will always get an unlimited amount of good randomness. Applications
who assume this are broken, and it has nothing to do with DOS attacks.
Note that even paranoid applicatons should not be using /dev/random
for session keys; again, /dev/random isn't magic, and entropy isn't
unlimited. Instead, such an application should pull 16 bytes or so,
and then use it to seed a cryptographic random number generator.
- Ted
--
What good does using multiple levels of RNG do? Why seed one RNG from another? Wouldn't it be better to have just one RNG that everybody uses? Doesn't the act of reading from the RNG add entropy to it, since no one reader has any idea how often and at what times other readers are stirring the pool? --
Not all applications need cryptographically secure random numbers. Sometimes, you just want a random number to seed your game RNG or a monte carlo simulator. --
No, unfortunately. The problem is that while in most typical cases may be true, the estimate of how much entropy we have has to be based on the assumption that everything we've done up to that point has been carefully orchestrated by the mortal enemy of whatever is currently asking us for entropy. While I don't have any easy solutions with obvious irrefutable technical brilliance or that will make everyone happy, I do think that one of the problems is that neither /dev/random nor /dev/urandom are guaranteed to provide what most people want. In the most common use case, you want crypographically-strong randomness even under the assumption that all previous activity is orchestrated by the enemy. Unfortunately, /dev/urandom will happily give you randomness worse than this while /dev/random will block even when you have it. DS --
Thanks for this pointer, I was not aware of the documentation. After reading this thread and the docs, I am now convinced that GnuTLS should seed a PRNG from /dev/(u)random instead of using the entropy directly. I will go filing a bug against GnuTLS. Greetings Marc -- ----------------------------------------------------------------------------- Marc Haber | "I don't trust Computers. They | Mailadresse im Header Mannheim, Germany | lose things." Winona Ryder | Fon: *49 621 72739834 Nordisch by Nature | How to make an American Quilt | Fax: *49 3221 2323190 --
BTW, note that it would be a polite thing for GnuTLS when it is encrpyting data, which represents information which might not be available to an adversary, and SHA1 hash it (out of paranoia) and feed it to /dev/random. This won't give any "credits" to the random entropy counter, but to the extent that is information that isn't available to the adversary, it adds additional uncertainty to the random pool. - Ted --
I have filed this as https://savannah.gnu.org/support/index.php?106113 Thanks for suggesting. Greetings Marc -- ----------------------------------------------------------------------------- Marc Haber | "I don't trust Computers. They | Mailadresse im Header Mannheim, Germany | lose things." Winona Ryder | Fon: *49 621 72739834 Nordisch by Nature | How to make an American Quilt | Fax: *49 3221 2323190 --
As reported about a month ago, the evidence is that the /dev/random stream is not cryptographically strong. Collecting uuids generated from the kernel uuid random generator from the random generator in the kernel shows abnormal patterns of duplicates. Alan --
Alan, are you sure you're not talking about Helge Deller's attempt to push a Time-based UUID generator into the kernel because you can get duplicates from the current userspace library? I've not heard of *any* claim where the kernel uuid random generator has been returning duplicates. - Ted P.S. Probably the right approach for Helge is to create a daemon started at boot time with privileges to write the appropriate state file to prevent duplicates across reboots, and then to change the uuid library to use the daemon if it is available (accessed via a Unix domain socket), or to use its existing algorithm (which is fine unless you have multiple threads wanting to generate large numbers of UUIDs per second in parallel), and you want to use time-based UUID's because they have better b-tree characteristics when you use them as indexes into a database. --
Before we added proper locking, it could theoretically happen on SMP with readers in lockstep. That was early 2.6. The only serious critique I know of is the Gutterman-Pinkas-Reinman paper which was a year out of date before publication. Now that another year has passed, perhaps I should respond to it.. -- Mathematics is the supreme nostalgia of our time. --
Then the original reports got lost somewhere. The Fedora tools use a kernel random uuid for system identifiers (to preserve anonymity while allowing system profiles etc to be generated and to know which are duplicates). We seen a huge number of duplicates for certain values: --
Pretty sad that such an interesting security bug didn't make it to It's possible that on machines with no real entropy, the initial startup seeds were having no effect on the /dev/urandom output. That's fixed here: http://www.kernel.org/hg/linux-2.6/rev/8298e254985e which would have been in v2.6.22-rc4 through the normal CVE process. The only other bits in there are wall time and utsname, so systems with no CMOS clock would behave repeatably. Can we find out what Any other details would be interesting. -- Mathematics is the supreme nostalgia of our time. --
We can but it will likely take a few weeks to get a good sampling. UUID is unique in the db so when someone checks in with the same UUID, the old one gets overwritten. I'll have to do regular copies of what the UUID holds over time. Smolt schedules a monthly check in which we We'll be able to get lots of stuff. Here's a profile of whats currently in e2b67e1d-e325-4740-b938-795addb45280. u_u_id: e2b67e1d-e325-4740-b938-795addb45280 o_s: Fedora release 7.92 (Rawhide) platform: i686 bogomips: 3660.33 system_memory: 2025 system_swap: 964 vendor: Sony Corporation system: VGN-FE31Z C3LMPJWX cpu_vendor: GenuineIntel cpu_model: Intel(R) Core(TM)2 CPU T num_cp_us: 2 cpu_speed: 1833 language: en_US.UT default_runlevel: 5 kernel_version: 2.6.23.1-23.fc8 formfactor: laptop last_modified: 2007-10-02 04:22:42 rating: 3 selinux_enabled: 1 selinux_enforce: targeted I'll grab the suspect UUID profiles over time to see what we end up with. -Mike --
Ok, I think I see whats going on here. I have some further investigation to do but it seems that the way our Live CD installer works is causing these issues. I'm going to try to grab some live CD's and hardware to confirm but at this point it seems thats whats going on. -Mike --
Alright, keep me posted. We probably need a scheme to make the initial seed more robust regardless of what you find out. -- Mathematics is the supreme nostalgia of our time. --
Ok, whats going on here is an issue with how the smolt RPM installs the
UUID and how Fedora's Live CD does an install. It's a complete false
alarm on the kernel side, sorry for the confusion.
-Mike
--
BTW, You may be better off using "uuidgen -t" to generate the UUID in
the smolt RPM, since that will use 12 bits of randomness from
/dev/random, plus the MAC, address and timestamp. So even if there is
zero randomness in /dev/random, and the time is January 1, 1970, at
least the MAC will contribute some uniqueness to the UUID.
- Ted
--
Right, but the MAC is globally unique (well, that's normally true) so it is an identifiable user characteristic, moreso than just a list of PCI device IDs sitting on a particular bus. It's silly, but there it is. Jon. --
Using MAC addresses -does- de-anonymize things though and presumably anonymous collection is a stated goal. -- Mathematics is the supreme nostalgia of our time. --
Right. And the more I think about it, the more I think the solution is going to be for the smolt server to generate the UUID and tell the client about it. Anything else seems to be based on hope, especially when you're installing via kickstart or similar type of process. Jon. --
True, but for many machines, the MAC address is enough for someone knowledgeable to (at least) determine what the manufacturer of your machine is, and in many cases, the model number of your laptop (since MAC addresses are assigned sequentially) and thus people can have a very good idea of the contents of your PCI tree ---- if for some reason anyone would even care, of course! - Ted --
We actually had a very vocal minority about all of that which ended up
putting us in the unfortunate position of generating a random UUID
instead of using a hardware UUID from hal :-/
-Mike
--
I do like that idea, and it could be combined with the DMI data for the system containing things like asset tracking numbers, etc. Could use HAL to generate a UUID based on hardware IDs and feed that in as entropy ;-) Jon. --
It might be better for us to just improve the pool initialization. That'll improve the out of the box experience for everyone. -- Mathematics is the supreme nostalgia of our time. --
I think we should re-evaluate having an internal path from the hwrngs to /dev/[u]random, which will reduce the need for userspace config that can go wrong. -- Mathematics is the supreme nostalgia of our time. --
That's a bit of a tangent on a tangent. :) Most people don't have a hardware RNG. But as long as there are adequate safeguards against common hardware failures (read: FIPS testing inside the kernel), go for it. Jeff --
We can do some internal whitening and some other basic tests (obviously not the full FIPS battery). The basic von Neumann whitening will do a great job of shutting off the spigot when an RNG fails in a non-nefarious way. And FIPS stuff is no defense against the nefarious failures anyway. But I think simply dividing our entropy estimate by 10 or so will go an awfully long way. -- Mathematics is the supreme nostalgia of our time. --
Agreed. The example program you posted does a very good job. I intuitively
thought that it would show best results where CPU clock >>> system clock,
but even with a faster clock (gettimeofday()) and a few tricks, it provides
an excellent whitened output even at high speed. In fact, it has the advantage
of automatically adjusting its speed to the source clock resolution, which
ensures we don't return long runs of zeroes or ones. Here's my slightly
modified version to extract large amounts of data from gettimeofday(),
followed by test results :
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
int get_clock()
{
struct timeval tv;
unsigned i;
gettimeofday(&tv, NULL);
i = tv.tv_usec ^ tv.tv_sec;
i = (i ^ (i >> 16)) & 0xffff;
i = (i ^ (i >> 8)) & 0xff;
i = (i ^ (i >> 4)) & 0xf;
i = (i ^ (i >> 2)) & 0x3;
i = (i ^ (i >> 1)) & 0x1;
return i;
}
int get_raw_timing_bit(void)
{
int parity = 0;
int start = get_clock();
while(start == get_clock()) {
parity++;
}
return parity & 1;
}
int get_whitened_timing_bit(void) {
int a, b;
while (1) {
// ensure we restart without the time offset from the
// failed tests.
get_raw_timing_bit();
a = get_raw_timing_bit();
b = get_raw_timing_bit();
if (a > b)
return 1;
if (b > a)
return 0;
}
}
int main(void)
{
int i;
while (1) {
for (i = 0; i < 64; i++) {
int j, k;
// variable-length eating 2N values per bit, looking
// for changing values.
do {
j = get_whitened_timing_bit();
k = get_whitened_timing_bit();
...Actually, most Business class laptops from IBM/Lenovo, HP, Dell,
Fujitsu, and Sony laptops *do* have TPM chips that among other things,
contain a slow but (supposedly, if the TPM microprocessors are to be
believed) secure hardware random number generator for use as a session
key generator. This is thanks to various US legal mandates, such as
HIPPA for the medical industry, and not just the paranoid ravings of
the MPAA and RIAA. :-)
The problem is enabling the TPM isn't trivial, and life gets harder if
you want the TPM chip to simultaneously work on dual-boot machines for
I think the userspace config problems were mainly due to the fact that
there wasn't a single official userspace utility package for the
random number package. Comments in drivers/char/random.c for how to
set up /etc/init.d/random is Just Not Enough.
If we had a single, official random number generator package that
contained the configuration, init.d script, as well as the daemon that
can do all sorts of different things that you really, Really, REALLY
want to do in userspace, including:
* FIPS testing (as Jeff suggested --- making sure what you think is
randomness isn't 60Hz hum is a Really Good Idea :-)
* access to TPM (if available --- I have a vague memory that you may
need access to the TPM key to access any of its functions, and the
the TPM key is stored in the filesystem)
So.... anyone interested in belling the metaphorical cat? :-)
- Ted
--
+1 agreed (not volunteering, but I will cheer on the hearty soul who undertakes this endeavor...) --
I remember having installed openssh on an AIX machines years ago, and being amazed by the number of sources it collected entropy from. Simple commands such as "ifconfig -a", "netstat -i" and "du -a", "ps -ef", "w" provided a lot of entropy. Regards, Willy --
Well.... not as many bits of entropy as you might think. But every little bit helps, especially if some of it is not available to adversary. - Ted --
I was always especially fond of the "du" entropy source with Solaris installations of OpenSSH (the PRNG used commands like "du" too). It was always amusing that a single network outage at the University would prevent anyone from ssh'ing into the "UNIX" machines. So yeah, if we want to take a giant leap backwards, I suggest jumping at this. Lots of these are not actually random - you can guess the free space on a network drive in some certain cases, you know what processes are likely to be created on a LiveCD, and many dmesg outputs are very similar, especially when there aren't precie timestamps included. But I do think it's time some of this got addressed :-) Cheers, Jon. --
heh, along those lines you could also do dmesg > /dev/random <grin> dmesg often has machine-unique identifiers of all sorts (including the MAC address, if you have an ethernet driver loaded) Jeff --
A good three-part solution would be: 1) Encourage distributions to do "dmesg > /dev/random" in their startup scripts. This could even be added to the kernel (as a one-time dump of the kernel message buffer just before init is started). 2) Encourage drivers to output any unique information to the kernel log. I believe all/most Ethernet drivers already do this with MAC addresses. Perhaps we can get the kernel to include CPU serial numbers and we can get the IDE/SATA drivers to include hard drive serial numbers. We can also use the TSC, where available, in early bootup, which measures exactly how long it took to get the kernel going, which should have some entropy in it. 3) Add more entropy to the kernel's pool at early startup, even if the quality of that entropy is low. Track it appropriately, of course. This should be enough to get cryptographically-strong random numbers that would hold up against anyone who didn't have access to the 'dmesg' output. DS --
I thought that /dev/random blocks when 0 entropy is available...? I'd expect uuid generation to block, not to issue duplicates. -- (english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html --
Background - Smolt runs this during its install: /bin/cat /proc/sys/kernel/random/uuid > /etc/sysconfig/hw-uuid For most users this would be run by the RPM %post scripts during install from anaconda. For some reason there are some UUID's (like those listed above) that come up more often then it seems they should if they are truly random. -Mike --
Would this be by any chance using kickstart where there is no user interaction, and no way of gathering entropy during the install process? The random number generator isn't *magic* you know.... - Ted --
This is certainly possible but I think its unlikely. Not many people know about smolt. Most of our profiles come from prompting people during firstboot which gets skipped when people are running kickstart. I'll make sure to follow up with people that report a duplicate. -Mike --
The original /dev/urandom behavior was to use all the entropy that was available, and then degrade into a pure PRNG when it was gone. The intent is for /dev/urandom to be precisely as strong as /dev/random when entropy is readily available. The current behavior is to deplete the pool when there is a large amount of entropy, but to always leave enough entropy for /dev/random to be read. This means we never completely starve the /dev/random side. The default amount is twice the read wakeup threshold (128 bits), settable in /proc/sys/kernel/random/. But there's really not much point in changing this threshold. If you're reading the /dev/random side at the same rate or more often that entropy is appearing, you'll run out regardless of how big your buffer is. -- Mathematics is the supreme nostalgia of our time. --
In another post I suggested having a minimum bound (use not entropy) and a maximum bound (grab some entropy) with the idea that between these values some limited entropy could be used. I have to wonder if the Right, my thought is to throttle user + urandom use such that the total stays below the available entropy. I had forgotten that that was a lower bound, although it's kind of an on-off toggle rather than proportional. Clearly if you care about this a *lot* you will use a hardware RNG. Thanks for the reminder on read_wakeup. -- Bill Davidsen <davidsen@tmr.com> "We have more to fear from the bungling of the incompetent than from the machinations of the wicked." - from Slashdot --
I didn't because I am not a regularly enough visitor of this mailing Would a PRNG that is frequently re-seeded from true entropy be unacceptable as well? Greetings Marc -- ----------------------------------------------------------------------------- Marc Haber | "I don't trust Computers. They | Mailadresse im Header Mannheim, Germany | lose things." Winona Ryder | Fon: *49 621 72739834 Nordisch by Nature | How to make an American Quilt | Fax: *49 3221 2323190 --
I don't see that he is proposing to change the interface, just how it gets the data it provides. Any program which depends on the actual data values it gets from urandom is pretty broken, anyway. I think that getting some entropy from network is a good thing, even if it's used only in urandom, and I would like a rational discussion of checking the random pool available when urandom is about to get random data, and perhaps having a lower and upper bound for pool size. That is, if there is more than Nmax random data urandom would take some, if there was less than Nmin it wouldn't, and between them it would take data, but less often. This would improve the urandom quality in the best case, and protect against depleting the /dev/random entropy in low entropy systems. Where's the downside? There has also been a lot of discussion over the years about improving the quality of urandom data, I don't personally think making the quality higher constitutes "changing a 12 years old and widely used userspace interface like /dev/urandom" either. Sounds like a local DoS attack point to me... -- Bill Davidsen <davidsen@tmr.com> "We have more to fear from the bungling of the incompetent than from the machinations of the wicked." - from Slashdot --
As long as /dev/random is readable for all users there's no reason to
use /dev/urandom for a local DoS...
cu
Adrian
--
"Is there not promise of rain?" Ling Tan asked suddenly out
of the darkness. There had been need of rain for many days.
"Only a promise," Lao Er said.
Pearl S. Buck - Dragon Seed
--
Draining entropy in /dev/urandom means that insecure and possibly not random data will be used and well thats a security bug if not a DoS bug. And yes this is by design, sigh. -- Never learn by your mistakes, if you do you may never dare to try again. --
Actually in modern 2.6 kernels there are two separate output entropy pools for /dev/random and /dev/urandom. So assuming that the adversary doesn't know the contents of the current state of the entropy pool (i.e., the RNG is well seeded with entropy), you can read all you want from /dev/urandom and that won't give an adversary successful information to attack /dev/random. - Ted --
Wouldn't it be possible to mix the data with the pid+uid of the reading process so that even if another one tries to collect data from urandom, he cannot predict what another process will get ? BTW, I think that the tuple (pid,uid,timestamp of open) is unpredictable and uncontrollable enough to provide one or even a few bits of entropy by itself. Regards, Willy --
Timestamp perhaps, but pid/uid are trivially guessable in automated environments, such as LiveCDs. And if you're also running on an embedded system without a RTC (common, folks like to save a few cents) then it's all pretty much "trivially" guessable on some level. Jon. --
My understanding was if you can drain entropy from /dev/urandom any futher reads from /dev/urandom will result in data which is not random at all. Is that wrong? Regards, ismail -- Never learn by your mistakes, if you do you may never dare to try again. --
Past a certain point /dev/urandom will stat returning results which are cryptographically random. At that point, you are depending on the strength of the SHA hash algorithm, and actually being able to not just to find hash collisions, but being able to trivially find all or most possible pre-images for a particular SHA hash algorithm. If that were to happen, it's highly likely that all digital signatures and openssh would be totally broken. - Ted --
The original point was that urandom draws entropy from random, and that it is an an inobvious and unintentional drain on the entropy pool. At least that's how I read it. I certainly have programs which draw on urandom simply because it's a convenient source of meaningless data. I have several fewer since this discussion started, though, now that I have looked at the easy alternatives. -- Bill Davidsen <davidsen@tmr.com> "Woe unto the statesman who makes war without a reason that will still be valid when the war is over..." Otto von Bismark --
And you are reading it correct. At least one of the major TLS libraries does it this way, putting unnecessary stress on the kernel entropy pool. While I now consider this a bug in the library, there surely are gazillions of similiarily flawed applications out there in the wild. Greetings Marc -- ----------------------------------------------------------------------------- Marc Haber | "I don't trust Computers. They | Mailadresse im Header Mannheim, Germany | lose things." Winona Ryder | Fon: *49 621 72739834 Nordisch by Nature | How to make an American Quilt | Fax: *49 3221 2323190 --
Some network drivers still feed entropy pools :
$ find drivers/net | xargs grep -n IRQF_SAMPLE_RANDOM
drivers/net/mv643xx_eth.c:1336: IRQF_SHARED |
IRQF_SAMPLE_RANDOM, dev->name, dev);
drivers/net/3c527.c:437: err = request_irq(dev->irq,
&mc32_interrupt, IRQF_SHARED | IRQF_SAMPLE_RANDOM, DRV_NAME, dev);
drivers/net/xen-netfront.c:1371:
IRQF_SAMPLE_RANDOM, netdev->name,
drivers/net/macb.c:1131: err = request_irq(dev->irq,
macb_interrupt, IRQF_SAMPLE_RANDOM,
drivers/net/tg3.c:7268: flags = IRQF_SAMPLE_RANDOM;
drivers/net/tg3.c:7273: flags = IRQF_SHARED | IRQF_SAMPLE_RANDOM;
drivers/net/tg3.c:7291: IRQF_SHARED |
IRQF_SAMPLE_RANDOM, dev->name, dev);
drivers/net/qla3xxx.c:3648: unsigned long irq_flags =
IRQF_SAMPLE_RANDOM | IRQF_SHARED;
drivers/net/3c523.c:292: ret = request_irq(dev->irq,
&elmc_interrupt, IRQF_SHARED | IRQF_SAMPLE_RANDOM,
drivers/net/cris/eth_v10.c:704: IRQF_SAMPLE_RANDOM,
cardname, (void *)dev)) {
drivers/net/atl1/atl1_main.c:1967: int irq_flags = IRQF_SAMPLE_RANDOM;
drivers/net/niu.c:4647: IRQF_SHARED |
IRQF_SAMPLE_RANDOM,
drivers/net/netxen/netxen_nic_main.c:866:
IRQF_SHARED|IRQF_SAMPLE_RANDOM, netdev->name,
drivers/net/ibmlana.c:784: result = request_irq(priv->realirq,
irq_handler, IRQF_SHARED | IRQF_SAMPLE_RANDOM, dev->name, dev);
So I guess you could patch your kernel to get more entropy sources (even
--
