Quantcast
Channel: Hacker News
Viewing all 25817 articles
Browse latest View live

What happens when patients find out how good their doctors are? (2004)

$
0
0

Every illness is a story, and Annie Page’s began with the kinds of small, unexceptional details that mean nothing until seen in hindsight. Like the fact that, when she was a baby, her father sometimes called her Little Potato Chip, because her skin tasted salty when he kissed her. Or that Annie’s mother noticed that her breathing was sometimes a little wheezy, though the pediatrician heard nothing through his stethoscope.

The detail that finally mattered was Annie’s size. For a while, Annie’s fine-boned petiteness seemed to be just a family trait. Her sister, Lauryn, four years older, had always been at the bottom end of the pediatrician’s growth chart for girls her age. By the time Annie was three years old, however, she had fallen off the chart. She stood an acceptable thirty-four inches tall but weighed only twenty-three pounds—less than ninety-eight per cent of girls her age. She did not look malnourished, but she didn’t look quite healthy, either.

“Failure to thrive” is what it’s called, and there can be scores of explanations: pituitary disorders, hypothyroidism, genetic defects in metabolism, inflammatorybowel disease, lead poisoning, H.I.V., tapeworm infection. In textbooks, the complete list is at least a page long. Annie’s doctor did a thorough workup. Then, at four o’clock on July 27, 1997—“I’ll never forget that day,” her mother, Honor, says—the pediatrician called the Pages at home with the results of a sweat test.

It’s a strange little test. The skin on the inside surface of a child’s forearm is cleaned and dried. Two small gauze pads are applied—one soaked with pilocarpine, a medicine that makes skin sweat, and the other with a salt solution. Electrodes are hooked up. Then a mild electric current is turned on for five minutes, driving the pilocarpine into the skin. A reddened, sweaty area about an inch in diameter appears on the skin, and a collection pad of dry filter paper is taped over it to absorb the sweat for half an hour. A technician then measures the concentration of chloride in the pad.

Over the phone, the doctor told Honor that her daughter’s chloride level was far higher than normal. Honor is a hospital pharmacist, and she had come across children with abnormal results like this. “All I knew was that it meant she was going to die,” she said quietly when I visited the Pages’ home, in the Cincinnati suburb of Loveland. The test showed that Annie had cystic fibrosis.

Cystic fibrosis is a genetic disease. Only a thousand American children per year are diagnosed as having it. Some ten million people in the United States carry the defective gene, but the disorder is recessive: a child will develop the condition only if both parents are carriers and both pass on a copy. The gene—which was discovered, in 1989, sitting out on the long arm of chromosome No. 7—produces a mutant protein that interferes with cells’ ability to manage chloride. This is what makes sweat from people with CF so salty. (Salt is sodium chloride, after all.) The chloride defect thickens secretions throughout the body, turning them dry and gluey. In the ducts of the pancreas, the flow of digestive enzymes becomes blocked, making a child less and less able to absorb food. This was why Annie had all but stopped growing. The effects on the lungs, however, are what make the disease lethal. Thickened mucus slowly fills the small airways and hardens, shrinking lung capacity. Over time, the disease leaves a child with the equivalent of just one functioning lung. Then half a lung. Then none at all.

The one overwhelming thought in the minds of Honor and Don Page was: We need to get to Children’s. Cincinnati Children’s Hospital is among the most respected pediatric hospitals in the country. It was where Albert Sabin invented the oral polio vaccine. The chapter on cystic fibrosis in the “Nelson Textbook of Pediatrics”—the bible of the specialty—was written by one of the hospital’s pediatricians. The Pages called and were given an appointment for the next morning.

“We were there for hours, meeting with all the different members of the team,” Honor recalled. “They took Annie’s blood pressure, measured her oxygen saturation, did some other tests. Then they put us in a room, and the pediatrician sat down with us. He was very kind, but frank, too. He said, ‘Do you understand it’s a genetic disease? That it’s nothing you did, nothing you can catch?’ He told us the median survival for patients was thirty years. In Annie’s lifetime, he said, we could see that go to forty. For him, he was sharing a great accomplishment in CF care. And the news was better than our worst fears. But only forty! That’s not what we wanted to hear.”

The team members reviewed the treatments. The Pages were told that they would have to give Annie pancreatic-enzyme pills with the first bite of every meal. They would have to give her supplemental vitamins. They also had to add calories wherever they could—putting tablespoons of butter on everything, giving her ice cream whenever she wanted, and then putting chocolate sauce on it.

A respiratory therapist explained that they would need to do manual chest therapy at least twice a day, half-hour sessions in which they would strike—“percuss”—their daughter’s torso with a cupped hand at each of fourteen specific locations on the front, back, and sides in order to loosen the thick secretions and help her to cough them up. They were given prescriptions for inhaled medicines. The doctor told them that Annie would need to come back once every three months for extended checkups. And then they went home to start their new life. They had been told almost everything they needed to know in order to give Annie her best chance to live as long as possible.

The one thing that the clinicians failed to tell them, however, was that Cincinnati Children’s was not, as the Pages supposed, among the country’s best centers for children with cystic fibrosis. According to data from that year, it was, at best, an average program. This was no small matter. In 1997, patients at an average center were living to be just over thirty years old; patients at the top center typically lived to be forty-six. By some measures, Cincinnati was well below average. The best predictor of a CF patient’s life expectancy is his or her lung function. At Cincinnati, lung function for patients under the age of twelve—children like Annie—was in the bottom twenty-five per cent of the country’s CF patients. And the doctors there knew it.

It used to be assumed that differences among hospitals or doctors in a particular specialty were generally insignificant. If you plotted a graph showing the results of all the centers treating cystic fibrosis—or any other disease, for that matter—people expected that the curve would look something like a shark fin, with most places clustered around the very best outcomes. But the evidence has begun to indicate otherwise. What you tend to find is a bell curve: a handful of teams with disturbingly poor outcomes for their patients, a handful with remarkably good results, and a great undistinguished middle.

In ordinary hernia operations, the chances of recurrence are one in ten for surgeons at the unhappy end of the spectrum, one in twenty for those in the middle majority, and under one in five hundred for a handful. A Scottish study of patients with treatable colon cancer found that the ten-year survival rate ranged from a high of sixty-three per cent to a low of twenty per cent, depending on the surgeon. For heartbypass patients, even at hospitals with a good volume of experience, risk-adjusted death rates in New York vary from five per cent to under one per cent—and only a very few hospitals are down near the one-per-cent mortality rate.

It is distressing for doctors to have to acknowledge the bell curve. It belies the promise that we make to patients who become seriously ill: that they can count on the medical system to give them their very best chance at life. It also contradicts the belief nearly all of us have that we are doing our job as well as it can be done. But evidence of the bell curve is starting to trickle out, to doctors and patients alike, and we are only beginning to find out what happens when it does.

In medicine, we are used to confronting failure; all doctors have unforeseen deaths and complications. What we’re not used to is comparing our records of success and failure with those of our peers. I am a surgeon in a department that is, our members like to believe, one of the best in the country. But the truth is that we have had no reliable evidence about whether we’re as good as we think we are. Baseball teams have win-loss records. Businesses have quarterly earnings reports. What about doctors?

There is a company on the Web called HealthGrades, which for $7.95 will give you a report card on any physician you choose. Recently, I requested the company’s report cards on me and several of my colleagues. They don’t tell you that much. You will learn, for instance, that I am in fact certified in my specialty, have no criminal convictions, have not been fired from any hospital, have not had my license suspended or revoked, and have not been disciplined. This is no doubt useful to know. But it sets the bar a tad low, doesn’t it?

In recent years, there have been numerous efforts to measure how various hospitals and doctors perform. No one has found the task easy. One difficulty has been figuring out what to measure. For six years, from 1986 to 1992, the federal government released an annual report that came to be known as the Death List, which ranked all the hospitals in the country by their death rate for elderly and disabled patients on Medicare. The spread was alarmingly wide, and the Death List made headlines the first year it came out. But the rankings proved to be almost useless. Death among the elderly or disabled mostly has to do with how old or sick they are to begin with, and the statisticians could never quite work out how to apportion blame between nature and doctors. Volatility in the numbers was one sign of the trouble. Hospitals’ rankings varied widely from one year to the next based on a handful of random deaths. It was unclear what kind of changes would improve their performance (other than sending their sickest patients to other hospitals). Pretty soon the public simply ignored the rankings.

Even with younger patients, death rates are a poor metric for how doctors do. After all, very few young patients die, and when they do it’s rarely a surprise; most already have metastatic cancer or horrendous injuries or the like. What one really wants to know is how we perform in typical circumstances. After I’ve done an appendectomy, how long does it take for my patients to fully recover? After I’ve taken out a thyroid cancer, how often do my patients have serious avoidable complications? How do my results compare with those of other surgeons?

Getting this kind of data can be difficult. Medicine still relies heavily on paper records, so to collect information you have to send people to either scour the charts or track the patients themselves, both of which are expensive and laborious propositions. Recent privacy regulations have made the task still harder. Yet it is being done. The country’s veterans’ hospitals have all now brought in staff who do nothing but record and compare surgeons’ complication rates and death rates. Fourteen teaching hospitals, including my own, have recently joined together to do the same. California, New Jersey, New York, and Pennsylvania have been collecting and reporting data on every cardiac surgeon in their states for several years.

One small field in medicine has been far ahead of most others in measuring the performance of its practitioners: cystic-fibrosis care. For forty years, the Cystic Fibrosis Foundation has gathered detailed data from the country’s cystic-fibrosis treatment centers. It did not begin doing so because it was more enlightened than everyone else. It did so because, in the nineteen-sixties, a pediatrician from Cleveland named LeRoy Matthews was driving people in the field crazy.

Matthews had started a cystic-fibrosis treatment program as a young pulmonary specialist at Babies and Children’s Hospital, in Cleveland, in 1957, and within a few years was claiming to have an annual mortality rate that was less than two per cent. To anyone treating CF at the time, it was a preposterous assertion. National mortality rates for the disease were estimated to be higher than twenty per cent a year, and the average patient died by the age of three. Yet here was Matthews saying that he and his colleagues could stop the disease from doing serious harm for years. “How long [our patients] will live remains to be seen, but I expect most of them to come to my funeral,” he told one conference of physicians.

In 1964, the Cystic Fibrosis Foundation gave a University of Minnesota pediatrician named Warren Warwick a budget of ten thousand dollars to collect reports on every patient treated at the thirty-one CF centers in the United States that year—data that would test Matthews’s claim. Several months later, he had the results: the median estimated age at death for patients in Matthews’s center was twenty-one years, seven times the age of patients treated elsewhere. He had not had a single death among patients younger than six in at least five years.

Unlike pediatricians elsewhere, Matthews viewed CF as a cumulative disease and provided aggressive treatment long before his patients became sick. He made his patients sleep each night in a plastic tent filled with a continuous, aerosolized water mist so dense you could barely see through it. This thinned the tenacious mucus that clogged their airways and enabled them to cough it up. Like British pediatricians, he also had family members clap on the children’s chests daily to help loosen the mucus. After Warwick’s report came out, Matthews’s treatment quickly became the standard in this country. The American Thoracic Society endorsed his approach, and Warwick’s data registry on treatment centers proved to be so useful that the Cystic Fibrosis Foundation has continued it ever since.

Looking at the data over time is both fascinating and disturbing. By 1966, mortality from CF nationally had dropped so much that the average life expectancy of CF patients had already reached ten years. By 1972, it was eighteen years—a rapid and remarkable transformation. At the same time, though, Matthews’s center had got even better. The foundation has never identified individual centers in its data; to insure participation, it has guaranteed anonymity. But Matthews’s center published its results. By the early nineteen-seventies, ninety-five per cent of patients who had gone there before severe lung disease set in were living past their eighteenth birthday. There was a bell curve, and the spread had narrowed a little. Yet every time the average moved up Matthews and a few others somehow managed to stay ahead of the pack. In 2003, life expectancy with CF had risen to thirty-three years nationally, but at the best center it was more than forty-seven. Experts have become as leery of life-expectancy calculations as they are of hospital death rates, but other measures tell the same story. For example, at the median center, lung function for patients with CF—the best predictor of survival—is about three-quarters of what it is for people without CF. At the top centers, the average lung function of patients is indistinguishable from that of children who do not have CF.

What makes the situation especially puzzling is that our system for CF care is far more sophisticated than that for most diseases. The hundred and seventeen CF centers across the country are all ultra-specialized, undergo a rigorous certification process, and have lots of experience in caring for people with CF. They all follow the same detailed guidelines for CF treatment. They all participate in research trials to figure out new and better treatments. You would think, therefore, that their results would be much the same. Yet the differences are enormous. Patients have not known this. So what happens when they find out?

In the winter of 2001, the Pages and twenty other families were invited by their doctors at Cincinnati Children’s to a meeting about the CF program there. Annie was seven years old now, a lively, brown-haired second grader. She was still not growing enough, and a simple cold could be hellish for her, but her lung function had been stable. The families gathered in a large conference room at the hospital. After a brief introduction, the doctors started flashing PowerPoint slides on a screen: here is how the top programs do on nutrition and respiratory performance, and here is how Cincinnati does. It was a kind of experiment in openness. The doctors were nervous. Some were opposed to having the meeting at all. But hospital leaders had insisted on going ahead. The reason was Don Berwick.

Berwick runs a small, nonprofit organization in Boston called the Institute for Healthcare Improvement. The institute provided multimillion-dollar grants to hospitals that were willing to try his ideas for improving medicine. Cincinnati’s CF program won one of the grants. And among Berwick’s key stipulations was that recipients had to open up their information to their patients—to “go naked,” as one doctor put it.

Berwick, a former pediatrician, is an unusual figure in medicine. In 2002, the industry publication Modern Healthcare listed him as the third most powerful person in American health care. Unlike the others on the list, he is powerful not because of the position he holds. (The Secretary of Health and Human Services, Tommy Thompson, was No. 1, and the head of Medicare and Medicaid was No. 2.) He is powerful because of how he thinks.

In December, 1999, at a health-care conference, Berwick gave a forty-minute speech distilling his ideas about the failings of American health care. Five years on, people are still talking about the speech. The video of it circulated like samizdat. (That was how I saw it: on a grainy, overplayed tape, about a year later.) A booklet with the transcript was sent to thousands of doctors around the country. Berwick is middle-aged, soft-spoken, and unprepossessing, and he knows how to use his apparent ordinariness to his advantage. He began his speech with a gripping story about a 1949 Montana forest fire that engulfed a parachute brigade of firefighters. Panicking, they ran, trying to make it up a seventy-six-per-cent grade and over a crest to safety. But their commander, a man named Wag Dodge, saw that it wasn’t going to work. So he stopped, took out some matches, and set the tall dry grass ahead of him on fire. The new blaze caught and rapidly spread up the slope. He stepped into the middle of the burned-out area it left behind, lay down, and called out to his crew to join him. He had invented what came to be called an “escape fire,” and it later became a standard part of Forest Service fire training. His men, however, either thought he was crazy or never heard his calls, and they ran past him. All but two were caught by the inferno and perished. Inside his escape fire, Dodge survived virtually unharmed.

As Berwick explained, the organization had unravelled. The men had lost their ability to think coherently, to act together, to recognize that a lifesaving idea might be possible. This is what happens to all flawed organizations in a disaster, and, he argued, that’s what is happening in modern health care. To fix medicine, Berwick maintained, we need to do two things: measure ourselves and be more open about what we are doing. This meant routinely comparing the performance of doctors and hospitals, looking at everything from complication rates to how often a drug ordered for a patient is delivered correctly and on time. And, he insisted, hospitals should give patients total access to the information. “ ‘No secrets’ is the new rule in my escape fire,” he said. He argued that openness would drive improvement, if simply through embarrassment. It would make it clear that the well-being and convenience of patients, not doctors, were paramount. It would also serve a fundamental moral good, because people should be able to learn about anything that affects their lives.

Berwick’s institute was given serious money from the Robert Wood Johnson Foundation to offer those who used his ideas. And so the doctors, nurses, and social workers of Cincinnati Children’s stood uncertainly before a crowd of patients’ families in that hospital conference room, told them how poorly the program’s results ranked, and announced a plan for doing better. Surprisingly, not a single family chose to leave the program.

“We thought about it after that meeting,” Ralph Blackwelder told me. He and his wife, Tracey, have eight children, four of whom have CF. “We thought maybe we should move. We could sell my business here and start a business somewhere else. We were thinking, Why would I want my kids to be seen here, with inferior care? I want the very best people to be helping my children.” But he and Tracey were impressed that the team had told them the truth. No one at Cincinnati Children’s had made any excuses, and everyone appeared desperate to do better. The Blackwelders had known these people for years. The program’s nutritionist, Terri Schindler, had a child of her own in the program. Their pulmonary specialist, Barbara Chini, had been smart, attentive, loving—taking their late-night phone calls, seeing the children through terrible crises, instituting new therapies as they became available. The program director, Jim Acton, made a personal promise that there would soon be no better treatment center in the world.

Honor Page was alarmed when she saw the numbers. Like the Blackwelders, the Pages had a close relationship with the team at Children’s, but the news tested their loyalty. Acton announced the formation of several committees that would work to improve the program’s results. Each committee, he said, had to have at least one parent on it. This is unusual; hospitals seldom allow patients and families on internal-review committees. So, rather than walk away, Honor decided to sign up for the committee that would reëxamine the science behind patients’ care.

Her committee was puzzled that the center’s results were not better. Not only had the center followed national guidelines for CF; two of its physicians had helped write them. They wanted to visit the top centers, but no one knew which those were. Although the Cystic Fibrosis Foundation’s annual reports displayed the individual results for each of the country’s hundred and seventeen centers, no names were attached. Doctors put in a call and sent e-mails to the foundation, asking for the names of the top five, but to no avail.

Several months later, in early 2002, Don Berwick visited the Cincinnati program. He was impressed by its seriousness, and by the intense involvement of the families, but he was incredulous when he learned that the committee couldn’t get the names of the top programs from the foundation. He called the foundation’s executive vice-president for medical affairs, Preston Campbell. “I was probably a bit self-righteous,” Berwick says. “I said, ‘How could you do this?’ And he said, ‘You don’t understand our world.’ ” This was the first Campbell had heard about the requests, and he reacted with instinctive caution. The centers, he tried to explain, give their data voluntarily. The reason they have done so for forty years is that they have trusted that it would be kept confidential. Once the centers lost that faith, they might no longer report solid, honest information tracking how different treatments are working, how many patients there are, and how well they do.

Campbell is a deliberate and thoughtful man, a pediatric pulmonologist who has devoted his career to cystic-fibrosis patients. The discussion with Berwick had left him uneasy. The Cystic Fibrosis Foundation had always been dedicated to the value of research; by investing in bench science, it had helped decode the gene for cystic fibrosis, produce two new drugs approved for patients, and generate more than a dozen other drugs that are currently being tested. Its investments in tracking patient care had produced scores of valuable studies. But what do you do when the research shows that patients are getting care of widely different quality?

A couple of weeks after Berwick’s phone call, Campbell released the names of the top five centers to Cincinnati. The episode convinced Campbell and others in the foundation that they needed to join the drive toward greater transparency, rather than just react. The foundation announced a goal of making the outcomes of every center publicly available. But it has yet to come close to doing so. It’s a measure of the discomfort with this issue in the cystic-fibrosis world that Campbell asked me not to print the names of the top five. “We’re not ready,” he says. “It’d be throwing grease on the slope.” So far, only a few of the nation’s CF treatment centers are committed to going public.

Still, after travelling to one of the top five centers for a look, I found I could not avoid naming the center I saw—no obscuring physicians’ identities or glossing over details. There was simply no way to explain what a great center did without the particulars. The people from Cincinnati found this, too. Within months of learning which the top five centers were, they’d spoken to each and then visited what they considered to be the very best one, the Minnesota Cystic Fibrosis Center, at Fairview-University Children’s Hospital, in Minneapolis. I went first to Cincinnati, and then to Minneapolis for comparison.

What I saw in Cincinnati both impressed me and, given its ranking, surprised me. The CF staff was skilled, energetic, and dedicated. They had just completed a flu-vaccination campaign that had reached more than ninety per cent of their patients. Patients were being sent questionnaires before their clinic visits so that the team would be better prepared for the questions they would have and the services (such as X-rays, tests, and specialist consultations) they would need. Before patients went home, the doctors gave them a written summary of their visit and a complete copy of their record, something that I had never thought to do in my own practice.

I joined Cori Daines, one of the seven CF-care specialists, in her clinic one morning. Among the patients we saw was Alyssa. She was fifteen years old, freckled, skinny, with nails painted loud red, straight sandy-blond hair tied in a ponytail, a soda in one hand, legs crossed, foot bouncing constantly. Every few minutes, she gave a short, throaty cough. Her parents sat to one side. All the questions were directed to her. How had she been doing? How was school going? Any breathing difficulties? Trouble keeping up with her calories? Her answers were monosyllabic at first. But Daines had known Alyssa for years, and slowly she opened up. Things had mostly been going all right, she said. She had been sticking with her treatment regimen—twice-a-day manual chest therapy by one of her parents, inhaled medications using a nebulizer immediately afterward, and vitamins. Her lung function had been measured that morning, and it was sixty-seven per cent of normal—slightly down from her usual eighty per cent. Her cough had got a little worse the day before, and this was thought to be the reason for the dip. Daines was concerned about stomach pains that Alyssa had been having for several months. The pains came on unpredictably, Alyssa said—before meals, after meals, in the middle of the night. They were sharp, and persisted for up to a couple of hours. Examinations, tests, and X-rays had found no abnormalities, but she’d stayed home from school for the past five weeks. Her parents, exasperated because she seemed fine most of the time, wondered if the pain could be just in her head. Daines wasn’t sure. She asked a staff nurse to check in with Alyssa at home, arranged for a consultation with a gastroenterologist and with a pain specialist, and scheduled an earlier return visit than the usual three months.

This was, it seemed to me, real medicine: untidy, human, but practiced carefully and conscientiously—as well as anyone could ask for. Then I went to Minneapolis.

The director of Fairview-University Children’s Hospital’s cystic-fibrosis center for almost forty years has been none other than Warren Warwick, the pediatrician who had conducted the study of LeRoy Matthews’s suspiciously high success rate. Ever since then, Warwick has made a study of what it takes to do better than everyone else. The secret, he insists, is simple, and he learned it from Matthews: you do whatever you can to keep your patients’ lungs as open as possible. Patients with CF at Fairview got the same things that patients everywhere did—some nebulized treatments to loosen secretions and unclog passageways (a kind of mist tent in a mouth pipe), antibiotics, and a good thumping on their chests every day. Yet, somehow, everything he did was different.

In the clinic one afternoon, I joined him as he saw a seventeen-year-old high-school senior named Janelle, who had been diagnosed with CF at the age of six and had been under his care ever since. She had come for her routine three-month checkup. She wore dyed-black hair to her shoulder blades, black Avril Lavigne eyeliner, four earrings in each ear, two more in an eyebrow, and a stud in her tongue. Warwick is seventy-six years old, tall, stooped, and frumpy-looking, with a well-worn tweed jacket, liver spots dotting his skin, wispy gray hair—by all appearances, a doddering, mid-century academic. He stood in front of Janelle for a moment, hands on his hips, looking her over, and then he said, “So, Janelle, what have you been doing to make us the best CF program in the country?”

“It’s not easy, you know,” she said.

They bantered. She was doing fine. School was going well. Warwick pulled out her latest lung-function measurements. There’d been a slight dip, as there was with Alyssa. Three months earlier, Janelle had been at a hundred and nine per cent (she was actually doing better than normal); now she was at around ninety per cent. Ninety per cent was still pretty good, and some ups and downs in the numbers are to be expected. But this was not the way Warwick saw the results.

He knitted his eyebrows. “Why did they go down?” he asked.

Janelle shrugged.

Any cough lately? No. Colds? No. Fevers? No. Was she sure she’d been taking her treatments regularly? Yes, of course. Every day? Yes. Did she ever miss treatments? Sure. Everyone does once in a while. How often is once in a while?

Then, slowly, Warwick got a different story out of her: in the past few months, it turned out, she’d barely been taking her treatments at all.

He pressed on. “Why aren’t you taking your treatments?” He appeared neither surprised nor angry. He seemed genuinely curious, as if he’d never run across this interesting situation before.

“I don’t know.”

He kept pushing. “What keeps you from doing your treatments?”

“I don’t know.”

“Up here”—he pointed at his own head—“what’s going on?”

I dont know,” she said.

He paused for a moment. And then he began speaking to me, taking a new tack. “The thing about patients with CF is that they’re good scientists,” he said. “They always experiment. We have to help them interpret what they experience as they experiment. So they stop doing their treatments. And what happens? They don’t get sick. Therefore, they conclude, Dr. Warwick is nuts.”

“Let’s look at the numbers,” he said to me, ignoring Janelle. He went to a little blackboard he had on the wall. It appeared to be well used. “A person’s daily risk of getting a bad lung illness with CF is 0.5 per cent.” He wrote the number down. Janelle rolled her eyes. She began tapping her foot. “The daily risk of getting a bad lung illness with CF plus treatment is 0.05 per cent,” he went on, and he wrote that number down. “So when you experiment you’re looking at the difference between a 99.95-per-cent chance of staying well and a 99.5-per-cent chance of staying well. Seems hardly any difference, right? On any given day, you have basically a one-hundred-per-cent chance of being well. But”—he paused and took a step toward me—“it is a big difference.” He chalked out the calculations. “Sum it up over a year, and it is the difference between an eighty-three-per-cent chance of making it through 2004 without getting sick and only a sixteen-per-cent chance.”

He turned to Janelle. “How do you stay well all your life? How do you become a geriatric patient?” he asked her. Her foot finally stopped tapping. “I can’t promise you anything. I can only tell you the odds.”

In this short speech was the core of Warwick’s world view. He believed that excellence came from seeing, on a daily basis, the difference between being 99.5-per-cent successful and being 99.95-per-cent successful. Many activities are like that, of course: catching fly balls, manufacturing microchips, delivering overnight packages. Medicine’s only distinction is that lives are lost in those slim margins.

And so he went to work on finding that margin for Janelle. Eventually, he figured out that she had a new boyfriend. She had a new job, too, and was working nights. The boyfriend had his own apartment, and she was either there or at a friend’s house most of the time, so she rarely made it home to take her treatments. At school, new rules required her to go to the school nurse for each dose of medicine during the day. So she skipped going. “It’s such a pain,” she said. He learned that there were some medicines she took and some she didn’t. One she took because it was the only thing that she felt actually made a difference. She took her vitamins, too. (“Why your vitamins?” “Because they’re cool.”) The rest she ignored.

Warwick proposed a deal. Janelle would go home for a breathing treatment every day after school, and get her best friend to hold her to it. She’d also keep key medications in her bag or her pocket at school and take them on her own. (“The nurse won’t let me.” “Don’t tell her,” he said, and deftly turned taking care of herself into an act of rebellion.) So far, Janelle was O.K. with this. But there was one other thing, he said: she’d have to come to the hospital for a few days of therapy to recover the lost ground. She stared at him.

“Today?”

“Yes, today.”

“How about tomorrow?”

“We’ve failed, Janelle,” he said. “It’s important to acknowledge when we’ve failed.”

With that, she began to cry.

Warwick’s combination of focus, aggressiveness, and inventiveness is what makes him extraordinary. He thinks hard about his patients, he pushes them, and he does not hesitate to improvise. Twenty years ago, while he was listening to a church choir and mulling over how he might examine his patients better, he came up with a new stethoscope—a stereo-stethoscope, he calls it. It has two bells dangling from it, and, because of a built-in sound delay, transmits lung sounds in stereo. He had an engineer make it for him. Listening to Janelle with the instrument, he put one bell on the right side of her chest and the other on her left side, and insisted that he could systematically localize how individual lobes of her lungs sounded.

He invented a new cough. It wasn’t enough that his patients actively cough up their sputum. He wanted a deeper, better cough, and later, in his office, Warwick made another patient practice his cough. The patient stretched his arms upward, yawned, pinched his nose, bent down as far as he could, let the pressure build up, and then, straightening, blasted everything out. (“Again!” Warwick encouraged him. “Harder!”)

He produced his most far-reaching invention almost two decades ago—a mechanized, chest-thumping vest for patients to wear. The chief difficulty for people with CF is sticking with the laborious daily regimen of care, particularly the manual chest therapy. It requires another person’s help. It requires conscientiousness, making sure to bang on each of the fourteen locations on a patient’s chest. And it requires consistency, doing this twice a day, every day, year after year. Warwick had become fascinated by studies showing that inflating and deflating a blood-pressure cuff around a dog’s chest could mobilize its lung secretions, and in the mid-nineteen-eighties he created what is now known as the Vest. It looks like a black flak jacket with two vacuum hoses coming out of the sides. These are hooked up to a compressor that shoots quick blasts of air in and out of the vest at high frequencies. (I talked to a patient while he had one of these on. He vibrated like a car on a back road.) Studies eventually showed that Warwick’s device was at least as effective as manual chest therapy, and was used far more consistently. Today, forty-five thousand patients with CF and other lung diseases use the technology.

Like most medical clinics, the Minnesota Cystic Fibrosis Center has several physicians and many more staff members. Warwick established a weekly meeting to review everyone’s care for their patients, and he insists on a degree of uniformity that clinicians usually find intolerable. Some chafe. He can have, as one of the doctors put it, “somewhat of an absence of, um, collegial respect for different care plans.” And although he stepped down as director of the center in 1999, to let a protégé, Carlos Milla, take over, he remains its guiding spirit. He and his colleagues aren’t content if their patients’ lung function is eighty per cent of normal, or even ninety per cent. They aim for a hundred per cent—or better. Almost ten per cent of the children at his center get supplemental feedings through a latex tube surgically inserted into their stomachs, simply because, by Warwick’s standards, they were not gaining enough weight. There’s no published research showing that you need to do this. But not a single child or teen-ager at the center has died in years. Its oldest patient is now sixty-four.

The buzzword for clinicians these days is “evidence-based practice”—good doctors are supposed to follow research findings rather than their own intuition or ad-hoc experimentation. Yet Warwick is almost contemptuous of established findings. National clinical guidelines for care are, he says, “a record of the past, and little more—they should have an expiration date.” I accompanied him as he visited another of his patients, Scott Pieper. When Pieper came to Fairview, at the age of thirty-two, he had lost at least eighty per cent of his lung capacity. He was too weak and short of breath to take a walk, let alone work, and he wasn’t expected to last a year. That was fourteen years ago.

“Some days, I think, This is it—I’m not going to make it,” Pieper told me. “But other times I think, I’m going to make sixty, seventy, maybe more.” For the past several months, Warwick had Pieper trying a new idea—wearing his vest not only for two daily thirty-minute sessions but also while napping for two hours in the middle of the day. Falling asleep in that shuddering thing took some getting used to. But Pieper was soon able to take up bowling, his first regular activity in years. He joined a two-night-a-week league. He couldn’t go four games, and his score always dropped in the third game, but he’d worked his average up to 177. “Any ideas about what we could do so you could last for that extra game, Scott?” Warwick asked. Well, Pieper said, he’d noticed that in the cold—anything below fifty degrees—and when humidity was below fifty per cent, he did better. Warwick suggested doing an extra hour in the vest on warm or humid days and on every game day. Pieper said he’d try it.

We are used to thinking that a doctor’s ability depends mainly on science and skill. The lesson from Minneapolis is that these may be the easiest parts of care. Even doctors with great knowledge and technical skill can have mediocre results; more nebulous factors like aggressiveness and consistency and ingenuity can matter enormously. In Cincinnati and in Minneapolis, the doctors are equally capable and well versed in the data on CF. But if Annie Page—who has had no breathing problems or major setbacks—were in Minneapolis she would almost certainly have had a feeding tube in her stomach and Warwick’s team hounding her to figure out ways to make her breathing even better than normal.

Don Berwick believes that the subtleties of medical decision-making can be identified and learned. The lessons are hidden. But if we open the book on physicians’ results, the lessons will be exposed. And if we are genuinely curious about how the best achieve their results, he believes they will spread.

The Cincinnati CF team has already begun tracking the nutrition and lung function of individual patients the way Warwick does, and is getting more aggressive in improving the results in these areas, too. Yet you have to wonder whether it is possible to replicate people like Warwick, with their intense drive and constant experimenting. In the two years since the Cystic Fibrosis Foundation began bringing together centers willing to share their data, certain patterns have begun to emerge, according to Bruce Marshall, the head of quality improvement for the foundation. All the centers appear to have made significant progress. None, however, have progressed more than centers like Fairview.

“You look at the rates of improvement in different quartiles, and it’s the centers in the top quartile that are improving fastest,” Marshall says. “They are at risk of breaking away.” What the best may have, above all, is a capacity to learn and adapt—and to do so faster than everyone else.

Once we acknowledge that, no matter how much we improve our average, the bell curve isn’t going away, we’re left with all sorts of questions. Will being in the bottom half be used against doctors in lawsuits? Will we be expected to tell our patients how we score? Will our patients leave us? Will those at the bottom be paid less than those at the top? The answer to all these questions is likely yes.

Recently, there has been a lot of discussion, for example, about “paying for quality.” (No one ever says “docking for mediocrity,” but it amounts to the same thing.) Congress has discussed the idea in hearings. Insurers like Aetna and the Blue Cross-Blue Shield companies are introducing it across the country. Already, Medicare has decided not to pay surgeons for intestinal transplantation operations unless they achieve a predefined success rate. Not surprisingly, this makes doctors anxious. I recently sat in on a presentation of the concept to an audience of doctors. By the end, some in the crowd were practically shouting with indignation: We’re going to be paid according to our grades? Who is doing the grading? For God’s sake, how?

We in medicine are not the only ones being graded nowadays. Firemen, C.E.O.s, and salesmen are. Even teachers are being graded, and, in some places, being paid accordingly. Yet we all feel uneasy about being judged by such grades. They never seem to measure the right things. They don’t take into account circumstances beyond our control. They are misused; they are unfair. Still, the simple facts remain: there is a bell curve in all human activities, and the differences you measure usually matter.

I asked Honor Page what she would do if, after all her efforts and the efforts of the doctors and nurses at Cincinnati Children’s Hospital to insure that “there was no place better in the world” to receive cystic-fibrosis care, their comparative performance still rated as resoundingly average.

“I can’t believe that’s possible,” she told me. The staff have worked so hard, she said, that she could not imagine they would fail.

After I pressed her, though, she told me, “I don’t think I’d settle for Cincinnati if it remains just average.” Then she thought about it some more. Would she really move Annie away from people who had been so devoted all these years, just because of the numbers? Well, maybe. But, at the same time, she wanted me to understand that their effort counted for more than she was able to express.

I do not have to consider these matters for very long before I start thinking about where I would stand on a bell curve for the operations I do. I have chosen to specialize (in surgery for endocrine tumors), so I would hope that my statistics prove to be better than those of surgeons who only occasionally do the kind of surgery I do. But am I up in Warwickian territory? Do I have to answer this question?

The hardest question for anyone who takes responsibility for what he or she does is, What if I turn out to be average? If we took all the surgeons at my level of experience, compared our results, and found that I am one of the worst, the answer would be easy: I’d turn in my scalpel. But what if I were a C? Working as I do in a city that’s mobbed with surgeons, how could I justify putting patients under the knife? I could tell myself, Someone’s got to be average. If the bell curve is a fact, then so is the reality that most doctors are going to be average. There is no shame in being one of them, right?

Except, of course, there is. Somehow, what troubles people isn’t so much being average as settling for it. Everyone knows that averageness is, for most of us, our fate. And in certain matters—looks, money, tennis—we would do well to accept this. But in your surgeon, your child’s pediatrician, your police department, your local high school? When the stakes are our lives and the lives of our children, we expect averageness to be resisted. And so I push to make myself the best. If I’m not the best already, I believe wholeheartedly that I will be. And you expect that of me, too. Whatever the next round of numbers may say. ♦


Reflecting on Haskell in 2017

$
0
0

Alas, another year has come and gone. It feels like just yesterday I was writing the last reflection blog post on my flight back to Boston for Christmas. I’ve spent most of the last year traveling and working in Europe, meeting a lot of new Haskellers and putting a lot of faces to names.

Haskell has had a great year and 2017 was defined by vast quantities of new code, including 14,000 new Haskell projects on Github . The amount of writing this year was voluminous and my list of interesting work is eight times as large as last year. At least seven new companies came into existence and many existing firms unexpectedly dropped large open source Haskell projects into the public sphere. Driven by a lot of software catastrophes, the intersection of security, software correctness and formal methods have been become quite an active area of investment and research across both industry and academia. It’s really never been an easier and more exciting time to be programming professionally in the world’s most advanced (yet usable) statically typed language.

Per what I guess is now a tradition, I will write my end of year retrospective on my highlights of what happened in the Haskell scene in retrospect.

Writing

The amount of Haskell writing this year was vast and it’s impossible to enumerate all of the excellent writing that occurred. Some of the truly exceptional bits that were drafted in 2017 included:

Books & Courses

Vladislav Zavialov and Artyom Kazak set out to write a book on the netherlands of Intermediate Haskell development, a mythical place that we all seemingly pass through but never speak of again. The project is intuitively called Intermediate Haskell and is slated to be released in 2018

Bartosz Milewski finished writing Category Theory for Programmers which is freely available and also generated as PDF.

Brent Yorgey drafted a new course for teaching introduction to Computer Science using Haksell at Hendrix University. Dmitry Kovanikov and Arseniy Seroka also drafted a course for a wide variety of intermediate to advanced Haskell topics at ITMO university. Some of which are in Russian but nevertheless большое письмо!

GHC

The Glorious Glasgow Haskell Compiler had it’s 8.2 release, and landed to much rejoicing. Major features such as unboxed sum types landed as planned in GHC 8.2. There were many longstanding issues that were closed and many miscellaneous fixes contributed in 2017. For instance GHC now uses alternative linkers such as ld.gold or ld.lld instead of the system default ld.

Semigroup is now a superclass of Monoid.

There was quite a bit of work on GHC cross compilation to ARM. The new build system Hadrian has been in work for the past three years, has was finally been merged into the GHC tree.

The DevOps Group has officially started and is being funded to help maintain the infrastructure used to host Haskell packages and build GHC. The general push of the group has been toward using hosted CI services, Appveyor and CircleCI and a greater use of more transparent platforms such as Github for GHC development.

There is work on a major refactor of the AST types to use the new Trees that Grow research to allow GHC API user to extend the AST for their own purposes,Eventually this may allow the split of the AST types out of the ghc package, allowing tooling authors, Template Haskell users, and the compiler itself to use the same AST representation.

GHC is partially accepting pull requests on Github although most of the development still occurs on the mailing list and Phabricator.

There was significant engineering effort to allow GHC to produce deterministic build artifacts to play nicely with caching reproducible build systems such as Buck and Bazel. Previously the emitted .hi files would contain non-deterministic data such as hashes, timestamps and unique name supply counts.

Errors

GHC 8.2 added wonderful new colorful error messages with caret diagnostics for syntax and type errors:

Colorful errors GHC 8.2

Compact Regions

Support for ‘Compact Regions’ landed in GHC 8.2. Compact regions are manually allocated regions where the data allocated inside it are compacted and not traversed by the GC. This is amenable for long-lived data structures that are resident in memory without mutation frequently occurring.

The interface can be accessed through the ghc-compact modules and used to create compact malloc’d memory.

import Control.DeepSeqimport Control.Exceptionimport qualifiedData.ByteString.Char8asBimport Data.Compact

main = compact (B.pack ['a'..'c'])

The test suite inside GHC maintains the best illustrations of it’s use for complex non-traditional data structures.

Type.Reflection

GHC added a new more expressive Typeable mechanism using the Type.Reflection module. typeRep can be applied with explicit type applications to arrows and functions can checked for type-level equality after application.

λ> typeRep @(->)
(->) 'LiftedRep 'LiftedRep
λ> typeRep @(MaybeInt) ==App (typeRep @Maybe) (typeRep @Int)True

Coercible

Not new to GHC 8.2 although the base library now exposes the Coercible constraints allowing polymorphism over types which have the same runtime representations to be safely coerced at runtime. This can also be extended to polymorphic functions which take a compile-time proof of the equivalence of two runtime data layouts.

import Data.CoercenewtypeMeters=MetersIntegerderiving (Num)newtypeFeet=FeetIntegerderiving (Num)f :: (Coercible a b, Num b) => a -> b -> b
f x y = coerce x + y
λ> f (Meters3) 47
λ> f (Feet3) 47
λ> f 4 (Feet3)Feet7

GHC tracks the usage (i.e. role) of type variables used as parameters as either nominalrepresentational or phantom allowing types that differ only in a phantom type of nominal parameters to be safely coerced.

Join Points

Luke Maurer and Simon Peyton Jones merged new work on join points which modifies GHC Core to optimize for join points in code. In Core, a join point is a specially tagged function whose only occurrences are saturated tail calls. In the actual GHC Core AST, a join point is simple bit of metadata indicated by IdDetails of the binder

Simon Peyton Jones presented the keynote at Haskell Exchange on his collaboration on Compiling without Continuation which present the ideas and core optimizations that are allowed by the new join points.

Deriving Strategies

In GHC 8.0 there were two alternative methods for automatic deriving of typeclass instances, using GeneralizedNewtypeDeriving and DeriveAnyClass. In addition there was also the wired-in deriving mechanisms for Show, Read, etc that were hardcoded into the compiler. These all used the same syntax and would conflict if multiple pragmas were enabled in a module.

The addition of DerivingStrategies allows us to disambiguate which deriving mechanism to use for a specific instance generation.

newtypeMeters=MetersIntderiving stock    (Read, Show)derivingnewtype  (Num)deriving anyclass (ToJSON, FromJSON)

Backpack

Edward Yang finished his PhD thesis on Backpack which was integrated in the GHC tree. The new branch adds support .bkp files, which specify abstract interfaces which can be instantiated in modules and used to construct Haskell modules which work polymorphically across multiple module instantiations.

For example an abstract string type can be written which operates over a module parameter `Str``:

unit abstract-str where
    signature StrwheredataStr        len ::Str->IntmoduleAStr (alen) whereimport Str        alen ::Str->Int
        alen = len

We can create (contrived) instantiations of this module for lists of ints and chars which expose a polymorphic length function over both.

unit str-string wheremoduleStrwheretypeStr=String        len ::Str->Int
        len = length

unit str-list wheremoduleStrwheretypeStr= [Int]        len ::Str->Int
        len = length

The modules can then be opened as speific namespaces with the exported functions able to be called over both module types.

unit main where
    dependency abstract-str[Str=str-string:Str] (AStr as AStr.Int)
    dependency abstract-str[Str=str-list:Str] (AStr as AStr.String)moduleMain (main) whereimport qualifiedAStr.Intimport qualifiedAStr.String        main ::IO ()
        main =do
            print $ AbstractStr.String.alen "Hello world"
            print $ AbstractStr.Int.alen [1, 2, 3]

With the latest GHC this can be compiled with the --backpack which generates the sum of all the hi files specified in the .bkp file and resolves values at link-time.

$ stack exec -- ghc --backpack example.bkp

While the functionality exists today, I’m not aware of any large projects using Backpack. Bolting this functionality onto an ecosystem that has spent a decade routing around many of the problems this system aims to solve, poses a huge engineering cost and may take a while to crystallize.

Summer of Haskell

Google lacked vision this year and did not sponsor the Haskell Organization for Summer of Code. But the program proceeded regardless with private sponsorship from industrial users. Fifteen students were paired with mentors and many successful projects and collaborations resulted.

LLVM

The LLVM bindings for Haskell saw quite a bit of work this year and were forked into a new organization llvm-hs and added support for LLVM 4.0 - 5.1:

  1. llvm-hs
  2. llvm-hs-pure
  3. llvm-hs-pretty

In a collaboration with Joachim Breitner and myself at Zurihac a type-safe LLVM library which embeds the semantics of LLVM instructions into the Haskell type-system was written.

Siddharth Brat started work on an STG to LLVM backend simplehxc before doing a rewrite in C++.

Moritz Angermann has been continuing to develop a Haskell library for emitting and reading LLVM Bitcode format as well as work on the llvm-ng backend which is a major rewrite of the GHC LLVM code generator.

Linear Types

Arnaud Spiwack prototyped a extension of GHC which augments the type system with linear types. Edsko de Vries wrote a detailed blog post about the nature of linearity and it’s uses.

The proposal extends the typing of functions to include linearity constraints on arrows, enforcing that variables or references are created and consumed with constrained reference counts. This allows us to statically enforce reference borrowing and allocations in the typechecker potentially allowing us to enforce lifetime constraints on closures and eliminating long-lived memory from being used with constructed unbounded lifetimes, thereby eliminating garbage collection for some Haskell functions.

For instance use of the linear arrow (a ->. b) can enrich the existing raw memory access functions enforcing the matching of allocation and free commands statically. The multiplicity of usage is either 0, 1 or ω and the linear arrow is syntatic sugar for unit multiplicity are aliases for (:'1 ->).

malloc ::Storable a => a ->. (Ptr a ->.Unrestricted b) ->.Unrestricted b
read ::Storable a =>Ptr a ->. (Ptr a, a)free ::Ptr a ->. ()

New abstractions such as movable, consumable and dupable references can be constructed out of existing class hierarchies and enriched with static linearity checks:

classConsumable a where  consume :: a ->. ()classConsumable a =>Dupable a where  dup :: a ->. (a, a)classDupable a =>Movable a where  move :: a ->.Unrestricted ainstanceDupable a =>Dupable [a] where
  dup [] = ([], [])
  dup (a:l) = shuffle (dup a) (dup l)where      shuffle :: (a, a) ->. ([a], [a]) ->. ([a], [a])
      shuffle (a, a') (l, l') = (a:l, a':l')instanceConsumable a =>Consumable [a] where
  consume [] = ()
  consume (a:l) = consume a `lseq` consume l

As part of the Summer of Haskell Edvard Hübinette used linear types to construct a safer stream processing library which can enforce resource consumption statically using linearity.

There is considerable debate about the proposal and the nature of integration of linear types into GHC. With some community involvement these patches could be integrated quite quickly in GHC.

LiquidHaskell

LiquidHaskell the large sutie of tools for adding refinement types to GHC Haskell continued development and became considerably more polished. At HaskellExchange several companies were using it in anger in production. For example, we can enforce statically the lists given at compile-time statically cannot contain certain values by constructing a proposition function in a (subset) of Haskell which can refine other definitions:

measure hasZero :: [Int] ->Prop
hasZero [] = false
hasZero (x:xs) = x ==0|| (hasZero xs)typeHasZero= {v : [Int] | (hasZero v)}-- Acceptedxs ::HasZero
xs = [1,2,3,4]-- Rejectedys ::HasZero
ys = [0,1,2,3]

This can be used to statically enforce that logic that consumes only a Just value can provably only be called with a Just with a isJust measure:

measure isJust :: forall a.Data.Maybe.Maybe a ->Bool
isJust (Data.Maybe.Just x)  = true 
isJust (Data.Maybe.Nothing) = false 

This year saw the addition of inductive predicates allowing more complex properties about non-arithmetic refinements to be checked. Including properties about lists

measure len :: [a] ->Int
len [] =0
len (x:xs) =1+ (len xs)-- Spec for Data.List exports refined types which can be statically refined with-- length constraints.
[] :: {v:[a]| len v =0}(:) :: _ -> xs:_ -> {v:[a]| len v =1+ len xs}append :: xs:[a] -> ys:[a] -> {v:[a]| len v = len xs + len ys}

The full library of specifications is now quite extensive and adding LiquidHaskell to an existing codebase is pretty seamelss

Foundation

Foundation is an alternative Prelude informed by modern design practices and data structures. It ships a much more sensible and efficient packed array of UTF8 points as it’s default String type. Rethinks the Numnumerical tower , and statically distinguishes partial functions. Also has fledgling documentation beyond just

Last year Foundation was a bit early, but this year at Zurihac several companies in London reported using it fully in production as a full industrial focused Prelude.

Editor Tooling

Editor integration improved, adding best in modern tooling to most of the common editors:

Atom

https://atom.io/packages/ide-haskell

Emacs

https://commercialhaskell.github.io/intero/

IntelliJ

https://plugins.jetbrains.com/plugin/8258-intellij-haskell

VSCode

https://marketplace.visualstudio.com/items?itemName=Vans.haskero

Sublime

https://packagecontrol.io/packages/SublimeHaskell

Monica Lent wrote a lovely post on the state of art in Vim and Haskell integration.

Rik van der Kleij has done an impressive amount of work adapting the IntellJ IDE to work with Haskell. Including a custom parser handling all of the syntax extensions, name lookup, Intero integration and integration with haskell-tools refactoring framework.

Development on the haskell-ide-engine has picked up again in the last few months.

Formal Methods

The DeepSpec, a collaboration between MIT, UPenn, Princeton and Yale, is working on a network of specification that span many compilers, languages and intermediate representations with the goal of achieving full functional correctness of software and hardware. Both Haskell and LLVM are part of this network of specifications. The group has successfully written a new formal calculus describing the GHC core language and proved it type sound in Coq. The project is called corespec and is described in the paper “A Specification for Dependent Types in Haskell”.

In addition the group also published a paper “Total Haskell is Reasonable Coq” and provided a utlity hs-to-coq which converts haskell code to equivalent Coq code.

The Galois group started formalizing the semantics of Cryptol, a compiler compiler for high-assurance cryptographic protocols which is itself written in Haskell.

Michael Burge wrote a cheeky article about extracting a specification for a “domain specific” browser from Coq into Haskell.

Pragma Proflieration & Prelude

Writing Haskell is almost trivial in practice. You just start with the magic fifty line {-# LANGUAGE ... #-} incantation to fast-forward to 2017, add then add 150 libraries that you’ve blessed by trial and error to your cabal file, and then just write down a single type signature whose inhabitant is Refl to your program. In fact if your program is longer than your import list you’re clearly doing Haskell all wrong.

In all seriousness, Haskell is not the small language it once was in 1998, it’s reach spans many industries, hobbyists, academia and many classes of people with different incentives and whose ideas about the future of the language are mutually incompatible. Realistically the reason why the Prelude and extension situation aren’t going to change anytime soon is that no one person or company has the economic means to champion such a change. It would be enormously expensive and any solution will never satisfy everyone’s concerns and desires. Consensus is expensive, while making everything opt-in is relatively cheap. This is ultimately the equilibrium we’ve converged on and baring some large sea change the language is going to remain in this equilibrium.

Haskell Survey

Taylor Fausak conducted an unofficial survey of Haskell users with some surprising results about widespread use of Haskell. Surprisingly there are reportedly 100 or more people who maintain 100,000 or more lines of Haskell code. Not so surprisingly most people have migrated to Stack while vim and emacs are the editors of choice.

While the majority of respondents are satisfied with Haskell the language the response are somewhat mixed the quality of libraries and the bulk of respondents reported Haskell libraries being undocumented , hard to usehard to find, and don’t integrate well.

Projects

Idris, the experimental dependently typed language, reached 1.0 release and became one of the larger languages which is itself written in Haskell.

The most prolific Haskell library Pandoc release it’s version 2.0.

Several other groups published new compilers in the Haksell-family of languages. Intel finally open sourced the Intell Haskell compiler which was a research project in more optimal compilation techniques. Morgan Stanley also released Hobbes a Haskell-like language used internally at the bank featuring several novel extensions to row-types and C++ FFI integration. A prototype Haskell compiler was also written in Rust.

The SMT solver integration library SBV saw a major rewrite of it’s internal and it’s old tactics system. The library is heavily used in various projects as an interface to Z3 and CVC4 solvers.

Uber released a library for parsing and analysis of Vertica, Hive, and Presto SQL queries.

Wire released the backend service to their commercial offering.

The Advanced Telematic Systems group in Berlin released a Quickcheck family library for doing for property testing of models about state machines. Bose also released Smudge a tool for doing developemtn and analysis of large state machines for hardware testing.

Florian Knupfer released a new high-performance HTML combinator library for templating.

Galois continued with HalVM unikernel continued development this year, and several HalVM Docker Imagaes were published allowing a very convenient way to write and test code against HalVM.

Facebook released a Haskell string parsing library duckling which parses human input into a restricted set of semantically tagged data. Facebook also prototyped a technique for hot-swapping Haskell code at runtime using clever GHC API trickery.

Chris Done released vado a browser engine written in Haskell.

Jonas Carpay released apecs an entity component system for game development in Haskell.

Csaba Hruska continued work on a GRIN compiler and code generator, an alternative core language for compiling lazy functional languages based on the work by Urban Boquist.

Dima Szamozvancev released mezzo a library and embedded domain-specific language for music description that can enforce rules of compositionality of music statically and prevent bad music from being unleashed on the world.

Conal Elliot and John Wiegley advanced a novel set of ideas on Compiling with Categories which allows the bidirectional representation of Haskell functions as categorical structures. Although currently implemented as a GHC typechecker extension it is a promising research area.

Harry Clarke published a paper on Generics Layout-Preserving Refactoring using a reprinter. i.e. a tool which takes a syntax tree, the original source file, and produces an updated source file which preserves secondary notation. This can be used to build tools like haskell-tools for arbitrary languages and write complicated refactoring suites.

Joachim Breitner contributed a prolific amount of open source projects including a new technique (ghc-proofs) for proving the equivalence of Haskell programs using a GHC plugin, (veggies) a verified simple LLVM code generator for GHC, and (inspection-testing) new technique for verifying properties of Core.

  1. veggies
  2. ghc-proofs
  3. inspecction-testing

The ghc-proofs plugin allows us to embed equation and relations into our Haskell module and potentially allow GHC to prove them correct by doing symbolic evaluation and evaluating them as far as possible and checking the equational relations of the equations sides. Right now it works for contrived and simple examples, but is quite a interesting approach that may yield further fruit.

{-# OPTIONS_GHC -O -fplugin GHC.Proof.Plugin #-}moduleSimplewhereimport GHC.Proofimport Data.Maybe

my_proof1 = (\f x -> isNothing (fmap f x))=== (\f x -> isNothing x)
$ ghc Simple.hs
[1 of 1] Compiling Simple           ( Simple.hs, Simple.o )GHC.Proof: Proving my_proof1 …
GHC.Proof proved 1 equalities

Haddock

Haddock is creaking at the seams. Most large Haskell projects (GHC, Stack, Agda, Cabal, Idris, etc) no longer use it for documentation. The codebase is dated and long standing issue like dealing with reexported modules are still open.

There is a large vacuum for a better solution to emerge and compatibility with RestructuredText would allow easy migration of existing documentation.

Databases

This year saw two new approaches to Haskell database integration:

  1. Selda - A library interacting with relational databases inspired by LINQ and Opaleye.
  2. Squel - A deep embedding of PostgreSQL in Haskell using generics-sop.

This still remains an area in the ecosystem where many solutions end up needlessly falling back to TemplateHaskell to generate data structures and typically tend to be a pain point. Both these libraries use generics and advanced type system features to statically enforce well-formed SQL query construction.

Data Science & Numerical Computing

Chris Doran presented a concise interpretation of Geometric Algebra, a generalization of linear algebra in terms of graded algebra written in Haskell. A talk on this project was presented at the Haskell Exchange.

At ZuriHac several people expressed interest in forming a Data Haskell organization to work on advancing the state of Haskell libraries for data science and macing learning. There is considerable interest of the constructing the right abstractions for a well-typed dataframe library.

Tom Nielson is furiously working on a suite of of projects, mostly related to data science, machine learning and statistics in Haskell.

The Accelerate project has been seeing a lot of development work recently and now has support for latest versions of LLVM and CUDA through llvm-hs project.

A group at the University of Gothenburg released TypedFlow a statically typed higher-order frontend to TensorFlow.

Eta

Typelead continued working on a Java Virtual Machine backend to GHC called Eta. The project has seen considerable amount of person-hours invested in compatibility and the firm has raised capital to pursue the project as a commercial venture.

The project does seem to be diverging from the Haskell mainline language in both syntax and semantics which raises some interesting questions about viability. Although the Haskell language standard seems to be stuck and not moving forward, so there’s an interesting conundrum faced by those trying to build on top of GHC in the long run.

WebAssembly

WebAssembly has been released and is supported by all major browsers as of December 2017. This is been piquing the interest of quite a few Haskellers (including myself) who have been looking for a saner way to interact with browsers than the ugly hack of ejecting hundreds of thousands of lines of generated Javascript source. WebAssembly in either standalone projects or as a target from GHC’s intermediate form STG to the browser offers an interesting path forward.

  1. Haskell WASM
  2. WebGHC
  3. ministgwasm
  4. forest-lang

Industry

An incomplete list of non-consulting companies who are actively using Haskell or have published Haskell open sources libraries follows:

Standard Chartered
Galois
Intel
Target
Uber
Vente Privee
FrontRow
NStack
Morgan Stanley
Takt
Fugue
Habito
Asahi Net
Sentenai
IOHK
Awake Networks
Facebook
Adjoint
DigitalAsset
AlphaSheets
Channable
SlamData
Wire
JP Morgan
Bose

There are three consulting companies also supporting Haskell in industry.

Well-Typed
Tweag
FP Complete

Conferences

Both the Haskell Exchange and ZuriHac conference had record attendance this year. Haskell was well-represented in many interdisciplinary conferences include StrangeLoop, CurryOn, LambdaDays, LambdaConf, and YOW.

Most of the videos are freely available online.

  1. Haskell Exchange Videos
  2. ComposeConf Videos
  3. ZuriHac Videos
  4. ICFP Videos

Haskellers by the lake in Rapperswil, Switzerland

In 2018 I have plans to visit Zurich, Sydney, Budapest, Amsterdam, San Francisco, Paris, Copenhagen and Tokyo this year. Hopefully I get to meet more Haskellers and share some ideas about the future of our beautiful language. Until then, Merry Christmas and Happy New Haskell Year.

Rust: Refactoring std for ultimate portability

$
0
0

Rust is really super portable. It supports a lot of platforms. But not enough ...
not nearly enough. Rust wants to be everywhere, in wild places that only
future generations will be able to imagine. We've got some work yet to enable
that future though, and it is our responsibility to the Rusting world to do so!

Rust has long been designed with portability at the forefront. It contains
relatively few designs that enforce hard restrictions on the underlying
plattform, and where it does there are potential strategies to reduce them. But
even though there isn't a great deal of platform-specificity bound to the heart
of Rust's design, the implementation itself - particularly of the standard
library - is tightly coupled to a number of underlying assumptions, most
obviously that it is running on something Windowsy or Unixy, that make further
porting unnecessarily difficult today.

There has been much discussion on this topic recently: an RFC about refactoring
std
, a request to merge a port for Redox, a port for Haiku, a port to
support Intel SGX, a port to Fuchsia, lamentations that porting std is a
quagmire.

Much of my work in the past has been in the organizition of std, and I've been
thinking about this a lot lately, and doing some prototyping. Herein I discuss
how to incrementally convert the Rust standard library into an ultra-portable,
ultra-composable runtime that is suitable for targetting the needs of most any
platform.

Goals

Many people have many ideas about where and how to port std. Here are some of
the potential goals:

  • Support for non-Unix, non-Windows platforms. There are a lot of possibilities
    for Rust in novel, future platforms.
  • Support for platforms that don't have or require libc. Web browsers (via wasm,
    without Emscripten) are one example, but there are others. The API surface is
    already designed to accomodate this, but not the implementation.
  • Reduced maintenance burden. Porting std today requires touching too many parts
    of the libraries, and those parts must be maintaned by the std maintainers. In
    general, day-to-day maintenance should not require dealing with
    platform-specific code, especially for lesser-maintained ports.
  • Reuse of std's components. There are projects that want to have a standard
    library, but std itself is not appropriate. Pieces like core and collections
    can already be reused, but it would be good if more of std was available as
    independent components.
  • Out-of-tree portability. Many future ports of std are quite speculative. We
    cannot maintain all of them in tree.
  • Strongly-typed portability. Relating to out-of-tree and reduced maintenance
    burden, it may be desirable to leverage the type system more to ensure the
    correctness of ports, e.g. by encoding the entire portability layer into
    traits.

To these ends my own personal goal is to create a clearly-defined interface
through which the standard library interoperates with the platform, one that is
easy to implement and maintain. I believe that achieving such an abstraction
layer is the first step to any further porting efforts, lest we cause a big
mess. That is the focus of the following discussion.

Platform-dependence in std

Before talking about solutions, some background on where std is tied to the
platform. When we are talking about the "platform" here we mostly mean "the
operating system", but also to some extent the runtime ABI. Concerns in these
two areas are generally governed by the target_os and target_env
configuration values, so generally when we are talking about platform
dependencies in std we are talking about areas of the code where those cfg
attributes are required (as well as cfg(unix) / cfg(windows), which are
shorthands for the aforementioned). Note that we are mostly not concerned with
code that only varies in definition based on target_arch: architecture porting
tends to be orthogonal to platform porting, and is more related to compiler
codegen support than runtime OS support.

The standard library is notably organized as a "facade": it is composed of a
number of small crates whose features are all reexported through the public
interface declared by std. Today, all of these inner crates (except for core)
are unstable implementation details. The purpose of this facade is mostly to,
through the use of the Rust crate DAG, strictly control the interdependencies
between the various independent units of functionality within the facade, and
thus make the individual facade crates maximally useful outside of std. Even
today these facade crates have minimal, well-defined dependencies and are highly
portable:

The std facade today

The things to notice about this illustration is that the white crates are
platform-independent, the black crates are platform-specific, and that std does
not actually depend on alloc_system and panic_unwind (explained
below).

Inside the facade

To understand the internal design of std it's important to recognize some things
about the language definition and its expectations from the runtime. The Rust
language itself imposes very few restrictions on the implementation of the
language runtime, but what it does expect are defined as "lang items". Lang
items (of which there are 79 defined today) are library routines that the
compiler generates code to call into to accomplish various things required by
the language semantics. A lang item may only be defined once globally, across
the entire crate DAG, and (more-or-less) they must all be defined somewhere in
the DAG in order for rustc to generate a runnable exe. Most lang items are
defined in the core library, which has no platform dependencies. There are a few
though that are tied to more complex runtime features of the language, most
notably allocation and unwinding, and much of the organization of the facade is
dedicated to providing to the language these features in well-factored ways. In
order to achieve this the facade in a number of places resorts to "magic",
implementation-specific features that are never intended to be stabilized; the
std facade makes incredibly heavy use of unstable features and will never be
buildable on stable Rust - it is highly coupled to the compiler
implementation. Sometimes this magic involves dependency inversion, where
interfaces are defined at lower levels, but the actual platform-specific
implementation is defined later in the dependency chain. Yet more dependency
inversion is going to be required for further abstracting std, though hopefully
no new "magic" features.

When it comes to platform abstraction, where the facade is most successful today
is with allocation and unwinding. Both features require access to the underlying
platform but are relatively self contained. And interestingly, both features
make heavy use of the aforementioned "magic", allowing the interfaces to be used
by the standard library, while the standard library itself does not actually
depend on the concrete implementation.

The interface to the allocator is defined by the alloc crate. Its only
dependency is core, and other than core this is the most important crate in
Rust: without allocation Rust is a limited language, and almost every crate
depends on it. Like core though, the alloc crate is still
platform-independent; it does not actually define the allocator, but it does
define the allocator interface, the Box, Rc, Arc types. Just these
features are enough to build most of the standard collections, which live in the
(still platform-independent) collections crate. The allocator itself is
defined in the alloc_system and alloc_jemalloc crates, which are
selected and linked in by the compiler only at the final link step via the
unstable mechanism described in RFC 1183. Dependency inversion for allocators
is accomplished through undefined symbols, where the allocator implementation is
accessed through symbols declared in the alloc crate but defined further
down the crate DAG.

Like the allocator crates, the unwinding implementations, panic_abort and
panic_unwind, employ magic to let the compiler know which one to link in,
and undefined symbols to achieve dependency inversion.

Both the alloctor and unwinding implementations have a dependency on libc.

In summary, within the facade the key language functionality provided by core,
alloc, and collections is written in platform-independent pure-Rust; the key
platform-specific runtime functionalities of allocation and unwinding are
isolated to the alloc_system, alloc_jemalloc, panic_unwind and
panic_abort crates; and dependency inversion prevents the platform-independent
crates from depending concretely on the platform-specific crates.

The standard library itself

Unfortunately, there is still a great deal of important standard library
functionality that is not so cleanly factored within the facade, and yet remains
entangled with platform-specific functionality. This is the major problem at
hand.

That's not to say though that std is utterly disorganized. On the contrary, we
have organized it fully with the intent of being portable. It's just not there
yet.

Within std, the sys module is where platform-specific code is intended to
reside. The sys module is implemented separately for Windows and for Unix,
under sys/windows and sys/unix. The sys_common module, on the other
hand, contains non-platform-specific code that supports the runtime
platform-abstraction needed by std. Unfortunately, today the separation of
responsibilities implied by this organization is not perfect, and there is
platform specific code elsewhere in std. There is a lint in-tree to enforce this
organization; its whitelist is a good view into the places where this
abstraction boundary is violated.

Worse than the bits of platform-specific code that reside outside of std::sys
though is the dependency graph between sys and the rest of std. Simply put,
it's a rat's nest: bidirectional dependencies abound between platform-specific
code and platform-dependent code. Breaking these dependencies is going to be the
principle challenge of making std more portable.

The contents of sys are implementation details of std but std does also
publicly expose platform-specific APIs in std::os. These generally reexport
from sys.

For the most part, except for std::os, the standard library does not expose
significant platform-specific behavior in its public interface. The one major
exception to this is std::path. This module is tailored quite specifically
to the intersection of Unix and Windows path handling.

Much of the platform-specific interdependencies in std are due to I/O and the
io::Error type, which is a unifying type across many modules. This may be a
legacy of std's former construction atop libuv, which is itself an I/O
abstraction layer. It may be that "standard I/O" should be thought of as a
single, mostly platform-specific, interdependent chunk that should live and port
together. Refactoring I/O is going to be the bulk of the work to make std more
portable.

A platform abstraction layer for std

Well, that's all background. Now lets talk about how to fulfill the promise of
portable std.

I want to paint you a picture of a utopia in which Rust has expanded to become
the fabric of the entire classical computing world, where the possibilities of
what we can achieve are not shackled to the decaying dreams of computer science
past. In this perfect utopia you have invented the perfect model for managing
your computer's sci-fi hardware, perfectly free from the legacy of Unix and
Windows. And you need the perfect language to write it in. Everywhere you look
is legacy: C, C++, Java; the stacks get bigger and bigger, cruft all the way
down.

The only shining light is Rust. Those Rustaceans have been chipping away the
cruft, distilling their platform to only the essence of bits and bytes, while
also expanding its expressive power toward legendary elegance. Rust doesn't want
to tell you how to build your system. Rust wants to serve you, to fulfill your
dreams, on your terms. For your ambitions, Rust is the only reasonable choice in
a world filled with compromises.

The work ahead is dead simple: all you have to do is provide an allocator, an
unwinder, and an implementation of the Rust platform abstraction layer. All
three of these things are their own crates, you just need to plug them into the
build. And as we'll see momentarily, to get started you don't even have to write
an allocator or an unwinder (utopic Rust has trivial default implementations
that will serve to get you started), so let's focus on getting that platform
abstraction layer up and running.

To get a sense of what we need to do, have a look at the utopic std facade:

The std facade tomorrow

The thing to notice here is the trinity of pal_common, pal_unix, and
pal_windows. This is the nexus of Rust std porting. Every function necessary
to run std on Unix is defined in pal_unix, and every function necessary to run
std on Windows is defined in pal_windows, and pal_common is their
platform-independent toolkit. The interface surface area is surprisingly
small: threading, concurrency, networking, process management, and a few other
bits and pieces. Both pal_unix and pal_windows implement the same interface,
consumed by std. (In the fullness of time there will certainly be other crates
involved in the deconstruction of std, but this simple division is sufficient to
understand the approach). So our only task is to implement pal_utopia, the
platform abstraction layer implementation for the OS of our dreams ("UtopiaOS"),
based on the well-trodden path laid out by other platforms before us.

It's a simple thing to create pal_utopia and get it building, just a few
steps:

  • Copy pal_example to pal_utopia. This creates a new PAL implementation that
    simply panics on all platform-specific invocations.
  • Create your riscv64-unknown-utopia target spec and set the alloctor to
    alloc_simple and the unwinder to unwind_simple. These are stock pure-Rust
    implementations of allocation and unwinding that rely only on the platform
    abstraction layer (simple unwinding is implemented through some portable code
    generation strategy, not DWARF).
  • Configure cargo to build std with your platform abstraction layer with crate
    replacement, configuring pal to be implemented by pal_utopia.

With std-aware cargo we can build the standard library out of tree, with stock
cargo, specifying our own pal crate. So now all you need to do is run cargo
build
against your own project and you've created a custom standard library. Of
course it does nothing useful yet, just panics. But the path is clear: run some
code, find the next panic, fill in some functions, repeat. That's it. Utopia.

OK, hopefully that got your imagination churning. There's all manner of fanciful
variations one could envision from there (I'll discuss some in a bit), and hopefully
you'll agree that a setup along these lines unlocks great possibilities.

The first step to utopia though is to get all that platform-specific code out of
std and isolated into a single crate.

Why put the PAL in crates?

The key to this future is having all platform-specific code in a single crate.
But because of interdependencies, especially within I/O code, getting there is
going to be non-trivial, requiring some advanced refactoring tricks, and in some
cases almost certainly causing the code to become more complex. Why is this
worth it?

First, crates are how we enforce constraints in Rust about which code can depend
on which other code, and we have strict constraints here. When you want to say
'this code must not depend on that code' you do it with crates. We do this
to excellent effect today with the std facade, so extracting the PAL is a
continuation of that design.

Second, it allows people to implement std out of tree. This will be a massive
enabler. It's simply unfeasible to do small-scale Rust experimentation with
novel platforms without this: today to port std one must either maintain their
own fork, or work upstream. This situation discourages people from even
attempting to port Rust. And furthermore, the Rust maintainers can't be expected
to entertain patches for every experimental port one might wish to pursue.

The cost of this is that the more complex subsystems in std will have at least
one extra layer of abstraction (though this should not impose any runtime cost).

How to get there

So the task at hand is more-or-less to extract sys/windows to pal_windows,
sys/unix to pal_unix, and anything they depend on to pal_common. There are
plenty of unknowns, so along the way we're going to learn a lot, but the
immediate path forward is relatively clear:

  • Move platform-specific code that does not live in sys/windows, sys/unix
    into those modules. This work can be driven off the whitelist in the PAL
    lint.
  • Extract std_common, std_windows, and std_unix, modifying both build
    systems as appropriate.
  • Begin teasing out the platform-specific parts of std::sys into the
    appropriate place in the PAL.

The good news is that I've already spent some time on a prototype. As part of
that work I already landed a tidy script to enforce where
platform-specific code may live in tree, and have another
in-flight to corral more code into std::sys. From this work I'm
encouraged that extracting all the platform-dependencies into their own crates
is possible.

I managed to extract quite a bit into the pal crates before getting sidetracked
on other matters. Unfortunately, I've stopped right at a critical junction of
figuring out how to extract io::Error which is the lynchpin of the
intertangled I/O code, but I think it's quite doable. My prototype is bitrotted
and will basically need to be redone to land, but it's probably good to look at
the commits to see the kind of work this will entail.

Dependency inversion

At the point where we extract io::Error is where we have to think hard about
"dependency inversion". What is that? Well, there are a bunch of systems in
std that have the following properties:

  • The bulk of the code is platform-independent
  • The code doesn't work without some platform-specific code
  • There is yet other platform-specific code that depends on it

This creates a situation where the subsystem wants to be defined once, in
pal_common, to avoid duplication; supplemented with additional code defined
downstream in pal_windows; instantiated for use in pal_windows; and finally
exported publicly in std. The dependency "inversion" is that the subsystem is
defined upstream of its dependency.

I said earlier that I stopped short of tackling the inversion necessary for
io::Error, but I did tackle one inversion: CStr/CString. This is a
simple case, but is illustrative, so I want to show what happened here, then
talk generally about techniques for dependency inversion.

The reason CString needs to be extracted from std is that various
platform-specific pieces of the PAL need to deal with C strings. And why does
CString require dependency inversion to extract? Because CString depends on
memchr, and memchr is platform-specific. Such a little thing, but big
consequences.

Before I explain how I did this I want to note that I would do it differently
the second time. Still, a good illustration.

In this version, c_str is its own crate, but that's only because it
has a minor (fixable) dependency on libc, and pal_common is not allowed to
depend on libc. One might expect it to ultimately be defined in pal_common
though.

The way I factored this was to define a platform-independent memchr
in pal_common. Then CStr and CString are defined in the c_str crate,
using the (possibly slow) platform-independent memchr. Now pal_unix and
pal_windows have access to the C string functionality they need via those types.

In std though, both types are redefined as a light wrapper around the
types defined previously, except that memchr is replaced with the
platform-specific implementations.

The unfortunate consequence of this approach is that all code in pal_unix and
pal_windows that use CString get the slow version of memchr. That's why I
said earlier that I would do this differently the next time. Instead, CString
wants to be instantiated in pal_windows and pal_unix using the fast version
of memchr (that is, the pal instantiates the platform-dependent type instead
of std), using one of the techniques I'll discuss below.

Now with that case illustrated, let's talk about general strategies for
dependency inversion. I'll keep using CString as an example.

Redefinition and IntoInner

Dependency inversion is already an important facet of platform-abstraction in
std. The pattern this most often takes inside std is through wrapping and
redefinition of inner types, and conversion between the two via the IntoInner
trait. You can see an example of this with net::TcpStream, which is a wrapper
around an inner sys_common::net::TcpStream.

This is basically what my CString example above does, though it doesn't literally
use the IntoInner trait.

The major downside of this is that it requires duplicating a lot of interface
surface: once at the lower layer, once again at the upper layer.

Generics

An obvious way to do dependecy inversion in Rust is through generics: you define
your type as generic over some trait that specifies the platform-specific functions
it needs to operate. So we might define CString like:

struct CString<M> where M: Memchr { ... }

Then the pal can instantiate it with its own Memchr implementation.

Of course, the real String in std is not generic, so std must then define its
own CString type that wraps the instantiation of the generic CString. So
this has a similar downside of requiring duplicate defenitions to achieve the
inversion.

Undefined symbols

The next approach is the classic systemsy way to do this - let the linker deal
with it. This is what the alloc crate does: declare some extern functions
that must implement some feature, and then have some downstream crate actually
define them.

So the c_str crate might declare:

extern "Rust" {
    #[no_mangle]
    fn __rust_pal_memchr(needle: u8, haystack: &[u8]) -> Option<usize>;
    #[no_mangle]
    fn __rust_pal_memrchr(needle: u8, haystack: &[u8]) -> Option<usize>;
}

Then pal_unix and pal_windows define them however they want.

This is a pretty good solution. The downsides though are that (unless using LTO)
no such functions will be inlinable; and there are some reasons for not wanting
the runtime to impose an excess of public symbols (I'm not clear on this point,
but it's something I've heard). It also doesn't work if your dependencies
themselves must be generic, though I doubt such things exist in the pal.

Macros

Finally, macros. The last ditch resort when the language doesn't do what you
want. To do this with macros, we would define a macro in pal_common that
accepts as arguments paths to all its platform-specific dependencies, then
pal_unix and pal_windows would instantiate those macros and reexport the
results for use by std.

So for CString:

macro_rules! pal_cstr {
    (memchr: $path) => {
        struct CString { ... }

        etc.
    }
}

This doesn't suffer from the problems the others do, but it does make the source
and the potential error messages for std hackers worse. I think this is the best
solution for tough cases.

Risks

The path forward here is pretty risk-free, and I want to emphasize that. We can
do quite a lot of experimentation here without committing long-term to anything.
The main risks are to do with the feasibility of a full extraction of
platform-specific code, and churn for unstable no-std consumers. It's possible
that we do the work of creating these extra crates, get pretty far into the process,
and hit some roadblock that makes the endeavor too difficult to complete.

I think the chances of that are unlikely - pretty much any factoring can be
achieved with more or less effort. If we were to hit such a roadblock it would
most likely to be for social reasons, a distaste for complicating the code
involved enough to achive the desired separation, or simply lack of will to put
in the effort.

Another risk is that the strategy won't actually get us to the end-goal
in a satisfactory way. Between std::os and std::path, std is committed to
not being perfectly platform-independent, and there may be other such platform
warts that arise in the porting.

One thing we could do to reduce risk is to not start by creating the pal crates
and instead do the refactoring to straighten out the dependencies within std,
only exploding them out into crates as the last step, when success is
assured. To do this we would need some analysis to enforce DAG-ness within a
crate, some new, unstable compiler feature. I'm not inclined to bother with this
though - the facade is unstable and we guarantee it will break, so let's break
stuff.

Future directions

This outlined just the initial work of creating the PAL crates, but there's more
that could be done. Here are a few ideas based on desires I've heard floating around:

  • The entire interface to pal can be turned into traits. This would make the exact
    interface required to port std more clearly defined.
  • The pal can be further split up so it can be reused in a more fine-grained manner, e.g.
    there might be a threading pal and an I/O pal.
  • Scenarios will allow std to be partially-defined for platforms that can't implement
    the whole surface, and those platforms will be free to partially-implement the pal.
  • We can create a pal_example crate that panics on every code path, that porters
    can work off of when starting a port.
  • We can create a simple, pure-Rust allocator that porters to non-libc systems can
    use before to get a system running, that depends only on sbrk/mmap, defined in
    the pal.
  • Likewise a simple unwinder that uses e.g. return-based unwinding so porters to
    unconventional systems don't have to immediately confrunt the hairy issues there.
  • We can create a port for Linux that doesn't use libc.
  • We can create a standard library for wasm that is tailored to the web platform,
    not the Unix platform.

Next steps and how to help right now

We can move in this direction now. As I've emphasized the risk here is low, and
we don't need to know the full path forward to make progress. There's a lot we
can do incrementally to move in this direction, and that is beneficial simply as
a matter of code cleanup. I'll keep doing so myself, though I can't promise to
dedicate any specific amount of time to it. If you want to help to there are
things you can do:

  • Bikeshed here!
  • Find parts of std that are platform-specific and not located in sys and move
    them there. Work to minimize the pal-tidy whitelist.
  • Untangle dependencies in std::sys, so that it only depends on code in
    sys_common, but not the rest of std. Modules in std::sys will eventually
    be lowered to pal_unix and pal_windows; and modules in std::sys_common
    to (more-or-less) pal_comon. You can see the unupstreamed work in my
    prototype for easy candidates.
  • Likewise, untangle dependencies in std::sys_common so they do not depend on
    the eitherstd::sys or the rest of std, again in preparation for moving
    to the platform-dependent pal_common crate.
  • Go ahead and introduce the pal_common, pal_unix and pal_windows
    crates. I expect that this step will require the most debate and coordination
    since we don't often change the std facade.
  • Begin moving code into the pal crates.
  • Figure out the refactoring sequence necessary to untangle the various I/O
    modules in std such that they can be extracted cleanly.

My aforementioned prototype contains a number of unupstreamed commits in this
direction that anybody can feel free to crib off of. If I were to start
upstreaming it I might use it as a guideline to sort out the dependencies within
std, without yet taking the step of extracting the pal crates.

Let's make Rust the best platform it can be!

A DSL for λ-terms in Scala

$
0
0

Ah, the lambda calculus—what a thing of beauty! It gives us the opportunity to write expressions like

(λm.λn.m(λi.λs.λz.is(sz)) n) (λs.λz.sz) (λs.λz.s(sz))

that some heresiarchs would stubbornly insist in obfuscating with the infidel’s notation as 1 + 2.

Unfortunately, things start to get unwieldy when you try to describe that thing in idiomatic Scala:

sealedtrait TermcaseclassVariable(name: Symbol)                   extends TermcaseclassAbstraction(param: Variable, body: Term) extends Termcaseclass Application(fn: Term, arg: Term)         extends Termval `1+2` =
  Application(
    Application(Abstraction(Variable('m),Abstraction(Variable('n),
          Application(
            Application(Variable('m),Abstraction(Variable('i),Abstraction(Variable('s),Abstraction(Variable('z),
                    Application(
                      Application( Variable('i), Variable('s) ),
                    Application( Variable('s), Variable('z) )))))),Variable('n)))),Abstraction(Variable('s),Abstraction(Variable('z),
            Application( Variable('s), Variable('z) )))),Abstraction(Variable('s),Abstraction(Variable('z),
        Application(Variable('s),
          Application( Variable('s), Variable('z) )))))

What a mess! It took me a lot to get that right for sure.

The good thing is that Scala’s syntax is flexible enough to let us design a nice-looking lambda calculus DSL embedded right into la langue de Odersky. Let’s see how.

Implicit variables

A bare symbol is good enough to visually identify a variable.

We can create an implicit conversion in Term’s companion object so the compiler does the wrapping for us whenever context asks for it:

object Term {implicitdefsymToVar(s: Symbol): Variable = Variable(s)
}

For example, the identity function can now be written as:

val I = Abstraction('x, 'x)

Infix applications

Scala doesn’t allow us to overload juxtaposition, but the next best thing we can do is to introduce an operator for function application. I’ll borrow Haskell’s dollar sign operator and implement it in the Term trait:

sealedtrait Term {def $(that: Term) = Application(this, that)
}

We can verify that $ associates from the left, as is the convention in the lambda calculus:

val t =  'a $  'b  $ 'cval l = ('a $  'b) $ 'cval r =  'a $ ('b  $ 'c)assert(t == l)assert(t != r)

It just takes one dollar to write the omega combinator:

valω = Abstraction('f, 'f $ 'f)

Lambdas, sweet lambdas

And the cherry on top of the cake: lambdas that look like lambdas! It’s just a matter of creating a function called λ that has two parameter lists: one for the parameter and one for the body.

We can also sprinkle some extra syntactic sugar on our cake by accepting more than one parameter and taking care of the currying. Yes, cake with curry!

defλ(p: Variable, ps: Variable*)(body: Term) =
  Abstraction(p, ps.foldRight(body) { (v, b) ⇒ Abstraction(v, b) })

Some classic combinators can finally be written in exquisite fashion:

val I = λ('x) { 'x }
val T = λ('x, 'y) { 'x }
val F = λ('x, 'y) { 'y }
val¬ = λ('p) { 'p $ F $ T }
valω = λ('f) { 'f $ 'f }
valΩ = ω $ ω
val S = λ('x, 'y, 'z) { 'x $ 'z $ ('y $ 'z) }

Putting one and two together

Let’s take our original expression:

(λm.λn.m(λi.λs.λz.is(sz)) n) (λs.λz.sz) (λs.λz.s(sz))

and see how it would translate to Scala now:

val `1+2` =λ('m, 'n) {
    'm $ ( λ('i, 's, 'z) { 'i $ 's $ ('s $ 'z) }) $ 'n
  } $ λ('s, 'z) { 's $ 'z } $ λ('s, 'z) { 's $ ('s $ 'z) }

Not bad! We can even give names to intermediate terms to make the meaning of the expression even clearer (not that we couldn’t have done this from the beginning, though):

val (s, m, i, n, z) = ('s, 'm, 'i, 'n, 'z)val one = λ(s, z) { s $ z }
val two = λ(s, z) { s $ (s $ z) }
val scc = λ(i, s, z) { i $ s $ (s $ z) }
val add = λ(m, n) { m $ scc $ n }
val onePlusTwo = add $ one $ two

This code would pass the strictest of code reviews with flying colors.

Doesn’t Scala already have lambdas?

Yes, and by using them we could have our expressions evaluated for free by the language.

But what I really want to do is to implement different evaluation strategies, and for that I need to manipulate the lambda terms myself. Hopefully that’ll give me material for future articles, in which I’ll show how to do impressive stuff like evaluating 1 + 2 to 3.

At least now I can write some nice-looking unit tests.

If you liked this article, you should follow me. I mean literally: wait for me to leave my home and walk behind me until I catch you.

Domogik: Take Control of Your Home

$
0
0

The butler Domogik assistant. Just talk to him or write to him to interact with it. An Android application let you talk in person with the butler and other interfaces will join over time.

It is very easy to extend and personalize your butler, be it by talking to him or even by editing a single file.

Control ...

What is the temperature in the living room

Domogik

The temperature in the living room is 21 degrees

Illuminate the living room.

Educate ...

How is the temperature outside ?

Domogik

I don't understand

When I say how is the temperature outside ? it means what is the temperature outside

How is the temperature outside ?

Domogik

The outside temperature is 13 degrees

Let us learn...

Domogik

Does this mean: What is the weather today?

Domogik

The sky will be mostly cloudy. Temperatures will be between 8 and 19 degrees.

Can i help you ....

Calculate 3 times 5 plus 4 minus 2

Domogik

3 + 4 * 5 - 2 = 21

Tell me what is the weight of an apple?

Sandboxing ImageMagick with nsjail

$
0
0

ImageMagick is the go-to image conversion library in many environments. It’s written in C and doesn’t have the best track record on security. Last year, a major vulnerability called ImageTragick (yes, there’s a logo) made the news. Even Facebook turned out to be vulnerable.

While secure alternatives exist, many existing projects have a hard dependency on ImageMagick and abstracting the image conversion can be quite involved. If you find yourself in a situation where you can’t avoid using ImageMagick, sandboxing can help you mitigate the damage in the event of a compromise.

Enter nsjail

nsjail, written by Google, calls itself “a light-weight process isolation tool.” It uses a number of Linux kernel features that allow users to isolate processes in dedicated namespaces, limit file system access, put constraints on their resource usage and to filter syscalls.

My goals for this sandbox can be broken down like this:

  • No network access — all images are local, so there’s no reason for ImageMagick to talk to anyone over the network
  • Read-only access to the binaries, library and configuration files and write access to the directory in which images live temporarily during conversion
  • Sane maximum execution times, somewhat limiting the impact of DoS attacks
  • Permit only a small subset of syscalls in order to reduce the overall attack surface (making it harder for attackers to escape the sandbox)

Most distributions don’t have nsjail packages yet, so we’ll need to build from source. We’ll start with the dependencies (assuming you’re on Debian or Ubuntu):

sudo apt install autoconf bison flex gcc g++ git libprotobuf-dev libtool make pkg-config protobuf-compiler

Next, we’ll clone the code and check out the latest release (that’s version 2.2 at the time of writing).

git clone https://github.com/google/nsjail.git
cd nsjail && git checkout 2.2

Building the project should be as simple as running make. This will produce ansjail binary in the same directory which you can then move to/usr/local/bin.

Some of the kernel features used by nsjail weren’t added until kernel 4.6, so you might have to update your kernel or distribution. nsjail also uses the user_namespaces feature, which is typically disabled. Append the following line to /etc/sysctl.conf to enable it:

kernel.unprivileged_userns_clone=1

Load the configuration change by rebooting your machine or use sudo sysctl -p.

Policy Configuration

nsjail helpfully includes a sample configuration for ImageMagick’s convert binary. This offers a good starting point for what we need. Much of the configuration depends on how your application uses ImageMagick. In my case, the application is Mastodon, via the popular paperclip gem for managing file attachments. Paperclip uses ImageMagick by shelling out to theconvert and identify binaries. That’s not a particularly clean way to use it, but it happens to make this task a bit easier.

You can skip to the end of this section if you just want a working nsjail configuration for Mastodon’s ImageMagick usage. If you’re running into issues with that configuration, reading this section will probably give you the tools you need for a fix.

Let’s start by looking at the sample configuration. The default values for things like time_limit seem good enough, so let’s leave them as-is. Next are a couple of mount directives which provide access to the file system. Most of them are read-only (no rw: true) and permit access to the ImageMagick binary and shared libraries. I happen to use a compiled version of ImageMagick that’s located in /usr/local/bin rather than /usr/bin, so I’ll need a mount for that. We’ll also want to permit access to the ImageMagick configuration files which are located in either /etc/ImageMagick-6 or /etc/ImageMagick-7.

Side note: ImageMagick’s policy configuration is another place where you can greatly reduce your attack surface. This is the configuration I use for Mastodon.

All of that leaves me with the following additional mount directives:

mount {
  src: "/usr/local/lib"
  dst: "/usr/local/lib"
  is_bind: true
  mandatory: false
}

mount {
  src: "/usr/local/bin/convert"
  dst: "/usr/local/bin/convert"
  is_bind: true
  mandatory: false
}

mount {
  src: "/etc/ImageMagick-6"
  dst: "/etc/ImageMagick-6"
  is_bind: true
  mandatory: false
}

mount {
  src: "/etc/ImageMagick-7"
  dst: "/etc/ImageMagick-7"
  is_bind: true
  mandatory: false
}

I also add mandatory: false to the existing /usr/bin/convert mount. That way, nsjail doesn’t throw an error if /usr/bin/convert doesn’t exist and I can go back and forth between compiled and packaged versions of ImageMagick without having to change the nsjail configuration.

Next, we’ll have to figure out where the files are stored while paperclip processes them. Paperclip helpfully logs every command it runs, so we can just grep for “Command” in our Rails logs and we’ll get something like this:

Command :: file -b --mime '/tmp/8d777f385d3dfec8815d20f7496026dc20171203-9975-dbjvvy.jpeg'
Command :: identify -format '%wx%h,%[exif:orientation]' '/tmp/8d777f385d3dfec8815d20f7496026dc20171203-9975-9mj1dj[0]' 2>/dev/null
Command :: identify -format %m '/tmp/8d777f385d3dfec8815d20f7496026dc20171203-9975-9mj1dj[0]'
Command :: convert '/tmp/8d777f385d3dfec8815d20f7496026dc20171203-9975-9mj1dj[0]' -auto-orient -resize "1280x1280>" -quality 90 -strip '/tmp/72dc008206075ad7e69b00a1e4f2544020171203-9975-1iywevw'

We can see that all the files are located in /tmp, so we’ll modify the existing /tmp mount to look like this:

mount {
  src: "/tmp"
  dst: "/tmp"
  rw: true
  is_bind: true
}

While we’re at it, let’s also remove the entire /Documents mount — we won’t be needing that.

The final section of the sample configuration is where we define our syscall filters. The sample configuration uses a blacklist approach which causes the process to be killed if it uses the ptrace, process_vm_readv orprocess_vm_writev syscalls. That’s better than nothing, but we can do better by using a whitelist of syscalls that we know ImageMagick needs, and killing the process if any other syscall is used.

Getting a list of the required syscalls is a bit involved. We can start by usingstrace -qcf followed by some of the commands we observed in our Rails log, using a couple of sample images in various formats. Our goal is to exercise all of the code paths ImageMagick will run in production, so make sure you use all the image formats and command variations you can find in your log. You might run something like:

strace -qcf convert '/tmp/input.png' -auto-orient -resize "1280x1280>" -quality 90 -strip '/tmp/output.png'

This will produce output similar to this:

% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
  0.00    0.000000           0        43           read
  0.00    0.000000           0         3           write
  0.00    0.000000           0        65        22 open
  0.00    0.000000           0        43           close
  0.00    0.000000           0        12         5 stat
  0.00    0.000000           0        51           fstat
  0.00    0.000000           0         9           lseek
  0.00    0.000000           0        76           mmap
  0.00    0.000000           0        58           mprotect
  0.00    0.000000           0         7           munmap
  0.00    0.000000           0         8           brk
  0.00    0.000000           0        11           rt_sigaction
  0.00    0.000000           0        19           rt_sigprocmask
  0.00    0.000000           0        31        29 access
  0.00    0.000000           0         1           execve
  0.00    0.000000           0         2           getdents
  0.00    0.000000           0         2           getrlimit
  0.00    0.000000           0         1           sysinfo
  0.00    0.000000           0        14           times
  0.00    0.000000           0         1           arch_prctl
  0.00    0.000000           0         1           futex
  0.00    0.000000           0         1           sched_getaffinity
  0.00    0.000000           0         1           set_tid_address
  0.00    0.000000           0         1           set_robust_list
------ ----------- ----------- --------- --------- ----------------
100.00    0.000000                   461        56 total

We’re interested in the syscall column, giving us a first set of syscalls for our seccomp-bpf policy. Let’s change the policy to use DEFAULT KILL and insert the extracted (comma-separated) syscalls:

seccomp_string: "POLICY imagemagick_convert {"
seccomp_string: "  ALLOW {"
seccomp_string: "    read, write, open, close, newstat, newfstat,"
seccomp_string: "    ... more syscalls ..."
seccomp_string: "  }"
seccomp_string: "}"
seccomp_string: "USE imagemagick_convert DEFAULT KILL"

strace uses a slightly different naming convention for some syscalls, so we’ll need to convert those manually. nsjail uses the Kafel language for its syscall filtering specification, so we’ll use the source file containing all syscalls as a reference. stat is called newstat in Kafel, fstat is newfstat, etc.

Let’s store what we have so far in a file in /etc/nsjail/imagemagick-convert.cfg and see if we can successfully run convert within nsjail:

nsjail --config /etc/nsjail/imagemagick-convert.cfg -- /usr/bin/convert '/tmp/input.png' -auto-orient -resize "1280x1280>" -quality 90 -strip '/tmp/output.png'

If you missed a syscall, or if strace did (don’t ask me why - it happens), you’ll see something like this in the output:

[W][1047] subprocSeccompViolation():258 PID: 1048 commited a syscall/seccomp violation and exited with SIGSYS

Finding the syscall that caused the violation can be done by usinggrep SECCOMP on your syslog or audit log. That should produce a log line like this:

type=SECCOMP msg=audit(1512341279.874:80142): auid=1000 uid=1000 gid=1000 ses=3 pid=1048 comm="convert" exe="/usr/bin/convert" sig=31 arch=c000003e syscall=158 compat=0 ip=0x7fa87097dbb8 code=0x0

Now we know the missing syscall has the number 158, which we can translate back to arch_prctl using the Kafel source file from earlier.

You’ll probably end up doing this a couple of times before the execution succeeds. This is the final syscall policy I ended up with:

seccomp_string: "POLICY imagemagick_convert {"
seccomp_string: "  ALLOW {"
seccomp_string: "    read, write, open, close, newstat, newfstat,"
seccomp_string: "    newlstat, lseek, mmap, mprotect, munmap, brk,"
seccomp_string: "    rt_sigaction, rt_sigprocmask, pwrite64, access,"
seccomp_string: "    getpid, execve, getdents, unlink, fchmod,"
seccomp_string: "    getrlimit, getrusage, sysinfo, times, futex,"
seccomp_string: "    arch_prctl, sched_getaffinity, set_tid_address,"
seccomp_string: "    clock_gettime, set_robust_list, exit_group,"
seccomp_string: "    clone, getcwd, pread64"
seccomp_string: "  }"
seccomp_string: "}"
seccomp_string: "USE imagemagick_convert DEFAULT KILL"

The full configuration for the convert binary can be found here. The same gist also includes a configuration for the identify binary.

Caging the Elephant

We now have a working nsjail configuration, but there’s one thing left to do: Getting Mastodon to use it. This is where paperclip shelling out to ImageMagick works in our favor — we’ll just create our own convert command that runs ImageMagick within a sandbox. Let’s create /usr/local/bin/nsjail-wrapper/convert with the following content:

#!/usr/bin/env bash
nsjail --quiet --config /etc/nsjail/imagemagick-convert.cfg -- /usr/bin/convert "$@"

Use chmod +x on the newly-created file and make sure to adjust the path from/usr/bin/convert if you use a compiled version of ImageMagick and .

Finally, we’ll need to get Mastodon to use this file rather than the one located in /usr/bin or /usr/local/bin. We do that by adding the following environment variable to the systemd services that run Mastodon:

Environment="PATH=/usr/local/bin/nsjail-wrapper:/usr/local/bin:/usr/bin:/bin"

If you’re following the default setup instructions for Mastodon, you’ll want to add that line to both /etc/systemd/system/mastodon-sidekiq.service and/etc/systemd/system/mastodon-web.service.

Reload systemd, restart the two services and you’re done:

sudo systemctl daemon-reload
sudo systemctl restart mastodon-sidekiq
sudo systemctl restart mastodon-web

It’s a good idea to periodically check your syslog (or audit log) for the string “SECCOMP” after you deploy this, or to have monitoring alert you to a match. Certain versions or configurations of ImageMagick might use syscalls that aren’t included in my policy, or you might deal with images that trigger a code path I haven’t run into yet. Remember that a policy violation might also be due to a malicious file, so be careful when adjusting the policy.

PoC > GTFO

It’s probably a good idea to test if our sandbox is working as intended. To do that, we’ll use the Proof of Concept available for the ImageTragick vulnerability, with some small adjustments to make it work in /tmp. We’ll need to build a vulnerable version of ImageMagick. I went with 6.8.5-10:

convert -version
Version: ImageMagick 6.8.5-10 2017-12-04 Q16 http://www.imagemagick.org
Copyright: Copyright (C) 1999-2013 ImageMagick Studio LLC
Features: DPC OpenMP Modules
Delegates: mpeg fontconfig freetype jbig jng jpeg lzma png ps x xml zlib

The PoC code uses the identify binary, so we’ll need the nsjail configuration from the earlier gist and the corresponding wrapper script. Running the PoC without having /usr/local/bin/nsjail-wrapper in my path, I now get the following result:

./test.sh
testing read
UNSAFE

testing delete
UNSAFE

testing http with local port: 27279
SAFE

testing http with nonce: 46648d3b
SAFE

testing rce1
UNSAFE

testing rce2
UNSAFE

testing MSL
UNSAFE

Evidently we’re vulnerable to some parts of ImageTragick. Next, let’s add /usr/local/bin/nsjail-wrapper back to our path and try again:

./test.sh
testing read
SAFE

testing delete
SAFE

testing http with local port: 45326
SAFE

testing http with nonce: 0fce39e0
SAFE

testing rce1
SAFE

testing rce2
SAFE

testing MSL
SAFE

Looks like we successfully mitigated ImageTragick! Our logs shows a bunch of lines like the following — the exploit code is trying to use the msync syscall and is subsequently killed:

type=SECCOMP msg=audit(1512348449.807:88531): auid=1000 uid=1000 gid=1000 ses=3 pid=5675 comm="identify" exe="/usr/local/bin/identify" sig=31 arch=c000003e syscall=26 compat=0 ip=0x7f6538695760 code=0x0

Performance Impact

Measuring the time it takes for a simple JPEG attachment to be processed and stored by paperclip, the average went from about 650 ms to 2100 ms. I suspect that most of the increase is due to paperclip shelling out to ImageMagick, which forces nsjail to build a new sandbox for every invocation. A daemon handling the conversion of many images would likely perform significantly better, perhaps even with no noticeable impact.

There is definitely room for improvement here, but given that image conversion as a whole barely makes a dent in the overall CPU budget of this service and that media uploads aren’t an area where users will get too frustrated because they’ll have to wait an additional second, it’s an acceptable trade-off.

Posted by on

The Trouble with Politicians Sharing Passwords

$
0
0

Yesterday I had a bunch of people point me at a tweet from a politician in the UK named Nadine Dorries. As it turns out, some folks were rather alarmed about her position on sharing what we would normally consider to be a secret. In this case, that secret is her password and, well, just read it:

For context, the back story to this is that another British pollie (Damian Green) is presently in hot water for allegedly accessing porn on his gov PC and Nadine is implying it could have been someone else on his PC using his identity. I read this while wandering around in LA on my way home from sitting in front of US Congress and explaining security principles to a government so it felt like a timely opportunity to share my own view on the matter:

And that would have pretty much been the end of it... but the topic kept coming up. More and more people pointed me to Nadine's tweet and the BBC also picked it up and quoted me. As I dug into her tweets (and those supporting her) while waiting for my bags back home in Australia, it became apparent this was becoming somewhat of a larger issue. I wanted to lay things out in a more cohesive fashion than tweets permit, which brings us to this post.

Other People Sharing Credentials

To be fair to Nadine, she's certainly not the only one handing her password out to other people. Reading through hundreds of tweets on the matter, there's a defence of "yeah but others do it too":

Firstly, that's not something I'd advise announcing in public because as you'll see a little later, admitting to that practice could have some rather severe consequences.

Secondly, the premise of justifying a bad practice purely on the basis of it being common is extremely worrying. It's normalising a behaviour that we should be actively working towards turning around. Particularly when we're talking about public figures in positions of influence, we need to see leadership around infosec, not acknowledgement that elected representatives are consciously exercising poor password hygiene.

What's the Problem Credential Sharing is Solving?

Let's start here because it's important to acknowledge that there's a reason Nadine (and others) are deliberately sharing their passwords with other people. If we can't get to grips with the root cause then we're not going to be able to effectively talk about the solutions.

Reading through the trove of tweets that followed, Nadine's challenge appears to be handling large volumes of email:

Let's be sympathetic to the challenge here - answering 300 emails a day would be a mammoth task and the principle of sourcing help from staffers is a perfectly reasonable one. Her approach to password sharing may simply be evidence of humans working around technology constraints:

I totally agree with the premise of technology needing to meet business requirements so let's take a look at how it does precisely that.

Understanding Delegated Access

As many people pointed out, there are indeed technology solutions available to solve this problem:

The concept of delegation hinges on someone else being able to perform duties on your behalf. How this is done depends on the technology of choice, for example in the Microsoft world there are a couple of ways to grant other people access. Firstly, you can share folders such that another party can access your mail. Now that's not strictly delegation (they can't act on your behalf), but it addresses use cases where someone else may need to access your messages (i.e. a personal assistant).

In order to truly delegate access to someone else, it only takes a few clicks:

Delegate access in Outlook

It's certainly not a concept unique to Microsoft either, it's actually a very well-established technology pattern to address precisely the scenario Nadine outlined above.

Other Collaborative Solutions

Let's not limit this discussion to just providing access to email though, there were other scenarios raised which may cause people to behave in a similar way to Nadine:

I really hope the suggestion of a security camera was tongue in cheek, although admittedly I did chuckle at the irony of this being a potential solution to regain the ability to identify users after consciously circumventing security controls!

But in answer to Picaro's question, yes, I have worked with a group of people all editing a document under separate identities. Products like SharePoint are designed to do precisely that and by their very nature are collaboration tools. If the logistics of this sounds confusing, check out the guidance around collaborating on Word documents with real-time co-authoring. Pictures speak a thousand words here:

444e4d41-c17e-4109-adc6-d715ebf6c299

51369e6d-c212-47f6-87e3-3d342d948956

8687d69e-a320-4f84-865d-51ca2a93252e

But again, this is far from being just a Microsoft construct and many readers here would have used Google Docs in the past which is also excellent for working collaboratively on content under unique identities. This is far from an unsolved technology problem. Indeed, the entire premise of many people within an organisation requiring access to common resources is an age-old requirement which has been solved many different ways by many different companies. There's certainly no lack of solutions here.

Identity, Accountability and Plausible Deniability

One of the constant themes that came back to me via Twitter was "plausible deniability":

Many others also suggested precisely this in replies to Nadine so let's look at exactly what's meant by the term:

Plausible deniability is the ability of people (typically senior officials in a formal or informal chain of command) to deny knowledge of or responsibility for any damnable actions committed by others in an organizational hierarchy because of a lack of evidence that can confirm their participation, even if they were personally involved in or at least willfully ignorant of the actions

The assertion here is that someone in her position could potentially say "something bad happened under my account but because multiple people use it, maybe it was someone else". The thing is, this is precisely the antithesis of identity and accountability and if this is actually a desirable state, then frankly there's much bigger problems at hand.

The situation with Damian Green trying to explain his way out of porn being on his machine perfectly illustrates the problem. The aforementioned BBC article contains a video where he says:

It is the truth that I didn't download or look at pornography on my computer

Yet - allegedly - pornography was found on his machine. The plausible deniability Nadine alludes to in her tweet is that how do you know it was him that downloaded it? I mean if many different people have the ability to operate under Damian's identity, that porn could have been downloaded by any number of people, right? Giving someone else access to your account leaves the door open to shirking responsibility when things go wrong.

The Ramifications of Providing Credentials to Other People

Here's an argument I've heard many times in the past:

The assertion here is that other people are already in positions of trust and as such, excessive permissions aren't a problem as you can rely on them to do the right thing. There are two fundamental flaws with this:

Firstly, there are plenty of people in positions of trust who haven't done the right thing. The most impactful example of this is Edward Snowden persuading NSA colleagues to provide their credentials to him. Now regardless of whether you do or don't support what Ed then did with those credentials, the point is that he was in a position where those around him trusted him - he had a security pass! You'll find many other examples ranging from system admins going rogue to insiders pilfering corporate documents for profit to the guy who outsourced his job to China so he could watch cat videos. Just because you trust them isn't sufficient reason to give them any more rights than they require to do their job.

Secondly, there are plenty of people who unwittingly put an organisation at risk due to having rights to things they simply don't need. I often hear an anecdote from a friend of mine in the industry where a manager he once knew demanded the same access rights as his subordinates because "I can tell them what to do anyway". That all unravelled in spectacular style when his teenage son jumped onto his machine one day and nuked a bunch of resources totally outside the scope of what the manager ever actually needed. We call the antidote for this the principle of least privilege and those inadvertent risks range from the example above to someone being infected with malware to phishing attacks. There's not necessary malice involved on behalf of the person with "a security pass", but the unnecessary trust placed in them heightens the risk.

In fact, social engineering is especially concerning in an environment where the sharing of credentials is the norm. When you condition people to treating secrets as no longer being secret but rather something you share with someone else that can establish sufficient trust, you open up a Pandora's box of possible problems because creating a veneer of authenticity in order to gain trust is precisely what phishers are so good at! Imagine an intern (per Nadine's original tweet) being asked for a password by someone posing as the boss in an environment where requesting this is the norm. You can see the problem.

In many organisations, there are very clear conditions of use set out for access to information systems that explicitly prohibit credential sharing. You know, organisations like the British Parliament:

Not sharing passwords

This is from the Advice for Members and their staff document on the UK Parliament Website and at least to my eyes, that seems like pretty explicit advice. Just in case it's not entirely clear, there's also the House of Commons Staff Handbook on Information Security Responsibilities:

House of Commons Staff Handbook

There are no accompanying caveats of "but it's alright if it makes things more convenient"! We all know this, not just because you might happen to occasionally read this blog but because we're constantly bombarded with this guidance both online and in the workplace:

Passwords are like toothbrushes

Lock your lips

We don't want to know

Oftentimes, the ramifications of deliberately circumventing security controls designed to protect the organisation can be severe:

If anyone knows what the possible repercussions for a member of parliament violating these policies are, do chime in via the comments section below.

Summary

I'm conscious the tweet that sparked this debate was made on a Saturday evening and for all I know, it could have been an off-handed comment after a bottle of chardonnay while kicking back on the couch. I also appreciate that for non-tech people this may have seemed like a perfectly reasonable approach at the time. A chorus of voices have now set her straight so I'm inclined to put more personal judgement on what happens next as opposed to what might have been nothing more than an uninformed casual comment.

But we do need to call out credential sharing in this fashion for what it is and it's precisely what I highlighted in that original tweet - lack of education. The Register piece I linked to earlier on quoted one MP as saying the following and it's hard not to agree with it in this case:

Most MPs have that fatal combination of arrogance, entitlement and ignorance, which mean they don't think codes of practice are for them

It's alarming to read that Nadine believes criticism of her approach is due to her gender because if ever there was a construct that's entirely gender-unbiased, it's access controls! Giving other people your credentials in a situation such as hers is a bad idea regardless of gender, race, sexuality and any other personal attribute someone may feel discriminated by.

With all of that said, if you're working in an environment where security controls are making it hard for you to do the very job you're employed to do, reach out to your IT department. In many cases there'll be solutions precisely like the delegated access explained above. It's highly likely that in Nadine's case, she can have her cake and eat it too in terms of providing staffers access to information and not breaking fundamental infosec principles.

The great irony of the debates justifying credential sharing is that they were sparked by someone attempting to claim innocence with those supporting him saying "well, it could have been someone else using his credentials"! This is precisely why this is problem! Fortunately, this whole thing was sparked by something as benign as looking at porn and before anyone jumps up and down and says that's actually a serious violation, when you consider the sorts of activities we task those in parliament with, you can see how behaviour under someone's identity we can't attribute back to them could be far, far more serious.

What Programming Languages Are Used Late at Night

$
0
0

Stack Overflow has a good post on which languages (or rather Stack Overflow tags) are used mostly during business hours, and which are used at night.

tsql, SharePoint, Java, etc. are used during the day, and Haskell is the clear favorite among night owls.

Haskell often catches flak for “being a hard language to hire programmers for.” This data suggests that, while there clearly aren’t as many Haskell programmers, many of them use it recreationally out of interest, not because it has the potential for a high salary. Such people would likely jump at an opportunity to do similar things during the day.

Would you hire such a person?

Hacker News discussion thread

Reddit discussion thread


'Snoopers' charter' changes put forward

$
0
0
Smartphone appsImage copyrightGetty Images
Image caption Communications services can be told to collect metadata

The government has proposed changes to the Investigatory Powers Act (IPA) after accepting that some parts of it are "inconsistent with EU law".

The IPA governs the collection and use of communications data by law enforcement agencies.

In December 2016, the Court of Justice of the European Union ruled that some aspects of the legislation were incompatible with EU law.

A public consultation on the proposed changes will run until 18 January.

Under the IPA, the secretary of state can order companies to keep communication metadata such as when, and to whom, messages were sent.

But the government accepted the IPA was inconsistent with EU law because:

  • law enforcement did not need to seek independent permission to access communications data
  • collecting communication metadata was not only reserved for the most serious crimes

To address those concerns, the government proposes:

  • that offences carrying a potential prison sentence of six months or more should be considered "serious crimes" for which communications data can be collected
  • that communications data will no longer be collected for the purpose of public health, collecting taxes or regulating financial markets
  • creating a new Office for Communications Data Authorisations (OCDA) that will authorise or decline law enforcement requests for data

It said creating the OCDA was a "significant" task that would require new premises, IT systems and staff.

The Open Rights Group described the changes as a "major victory" but said it wanted further amendments.

"Adding independent authorisation for communications data requests will make the police more effective, as corruption and abuse will be harder," it said in a blog post.

"Nevertheless, the government has disregarded many key elements of the judgment. It isn't going to reduce the amount of data retained."

The public has until 18 January to submit comments on the proposals to the government.

Introducing Messenger Kids

$
0
0

By Loren Cheng, Product Management Director

Today, in the United States, we’re rolling out a preview of Messenger Kids, a new app that makes it easier for kids to safely video chat and message with family and friends when they can’t be together in person. After talking to thousands of parents, associations like National PTA, and parenting experts in the US, we found that there’s a need for a messaging app that lets kids connect with people they love but also has the level of control parents want.

To give kids and parents a fun, safer solution, we built Messenger Kids, a standalone app that lives on kids’ tablets or smartphones but can be controlled from a parent’s Facebook account. Whether it’s using video chat to talk to grandparents, staying in touch with cousins who live far away, or sending mom a decorated photo while she’s working late to say hi, Messenger Kids opens up a new world of online communication to families. This preview is available on the App Store for iPad, iPod touch, and iPhone.

Co-Developed With Parents, Kids and Experts

Today, parents are increasingly allowing their children to use tablets and smartphones, but often have questions and concerns about how their kids use them and which apps are appropriate. So when we heard about the need for better apps directly from parents during research and conversations with parents, we knew we needed to develop it alongside with the people who were going to use it, as well as experts who could help guide our thinking.

In addition to our research with thousands of parents, we’ve engaged with over a dozen expert advisors in the areas of child development, online safety, and children’s media and technology who’ve helped inform our approach to building our first app for kids. We’ve also had thought-provoking conversations around topics of responsible online communication, parental controls, and much more with organizations like National PTA and Blue Star Families, where we heard first hand how parents and caregivers approach raising children in today’s digitally connected world.

And for the past several months, many families at Messenger and Facebook have used the app and helped come up with some of the key features like the easy-to-use parental controls.

More Fun For Kids, More Control For Parents

Messenger Kids is full of features for kids to connect with the people they love. Once their account is set up by a parent, kids can start a one-on-one or group video chat with parent-approved contacts. The home screen shows them at a glance who they are approved to talk to, and when those contacts are online.

Playful masks, emojis and sound effects bring conversations to life.

In addition to video chat, kids can send photos, videos or text messages to their parent-approved friends and adult relatives, who will receive the messages via their regular Messenger app.

A library of kid-appropriate and specially chosen GIFs, frames, stickers, masks and drawing tools lets them decorate content and express their personalities.

Messenger Kids gives parents more control. Parents fully control the contact list and kids can’t connect with contacts that their parent does not approve. Parents control kids accounts and contacts through the Messenger Kids Controls panel in their main Facebook app:

How to Get Started

Every child account on Messenger Kids must be set up by a parent. For parents, setting your child up with a Messenger Kids account is done in four steps:

  1. Download: First, download the Messenger Kids app on your child’s iPad, iPod touch, or iPhone from the App Store.
  2. Authenticate: Then, authenticate your child’s device using your own Facebook username and password. This will not create a Facebook account for your child or give them access to your Facebook account.
  3. Create an account: Finish the setup process by creating an account for your child, where all you’ll need to do is provide their name. Then the device can be handed over to the child so they can start chatting with the family and friends you approve.
  4. Add contacts: To add people to your child’s approved contact list, go to the Messenger Kids parental controls panel in your main Facebook app. To get there, click on “More” on the bottom right corner in your main Facebook app, and click “Messenger Kids” in the Explore section.

More Information and What’s Next

There are no ads in Messenger Kids and your child’s information isn’t used for ads. It is free to download and there are no in-app purchases. Messenger Kids is also designed to be compliant with the Children’s Online Privacy and Protection Act (COPPA).

This preview of Messenger Kids is only available in the US at this time on the Apple App Store, and will be coming to Amazon App Store and Google Play Store in the coming months.

We’ve worked extensively with parents and families to shape Messenger Kids and we’re looking forward to learning and listening as more children and families start to use the iOS preview.

For more specific information about the app, visit messengerkids.com.

National PTA does not endorse any commercial entity, product, or service. No endorsement is implied.

My 20-Year Experience of Software Development Methodologies

$
0
0

Recently I read Sapiens: A Brief History of Humankind by Yuval Harari. The basic thesis of the book is that humans require ‘collective fictions’ so that we can collaborate in larger numbers than the 150 or so our brains are big enough to cope with by default. Collective fictions are things that don’t describe solid objects in the real world we can see and touch. Things like religions, nationalism, liberal democracy, or Popperian falsifiability in science. Things that don’t exist, but when we act like they do, we easily forget that they don’t.

Collective Fictions in IT – Waterfall

This got me thinking about some of the things that bother me today about the world of software engineering. When I started in software 20 years ago, God was waterfall. I joined a consultancy (ca. 400 people) that wrote very long specs which were honed to within an inch of their life, down to the individual Java classes and attributes. These specs were submitted to the customer (God knows what they made of it), who signed it off. This was then built, delivered, and monies were received soon after. Life was simpler then and everyone was happy.

Except there were gaps in the story – customers complained that the spec didn’t match the delivery, and often the product delivered would not match the spec, as ‘things’ changed while the project went on. In other words, the waterfall process was a ‘collective fiction’ that gave us enough stability and coherence to collaborate, get something out of the door, and get paid.

This consultancy went out of business soon after I joined. No conclusions can be drawn from this.

Collective Fictions in IT – Startups ca. 2000

I got a job at another software development company that had a niche with lots of work in the pipe. I was employee #39. There was no waterfall. In fact, there was nothing in the way of methodology I could see at all. Specs were agreed with a phone call. Design, prototype and build were indistinguishable. In fact it felt like total chaos; it was against all of the precepts of my training. There was more work than we could handle, and we got on with it.

The fact was, we were small enough not to need a collective fiction we had to name. Relationships and facts could be kept in our heads, and if you needed help, you literally called out to the room. The tone was like this, basically:

pm

Of course there were collective fictions, we just didn’t name them:

  • We will never have a mission statement
  • We don’t need HR or corporate communications, we have the pub (tough luck if you have a family)
  • We only hire the best

We got slightly bigger, and customers started asking us what our software methodology was. We guessed it wasn’t acceptable to say ‘we just write the code’ (legend had it our C-based application server – still in use and blazingly fast – was written before my time in a fit of pique with a stash of amphetamines over a weekend. It’s still in use.)

Turns out there was this thing called ‘Rapid Application Development’ that emphasized prototyping. We told customers we did RAD, and they seemed happy, as it was A Thing. It sounded to me like ‘hacking’, but to be honest I’m not sure anyone among us really properly understood it or read up on it.

As a collective fiction it worked, because it kept customers off our backs while we wrote the software.

Soon we doubled in size, moved out of our cramped little office into a much bigger one with bigger desks, and multiple floors. You couldn’t shout out your question to the room anymore. Teams got bigger, and these things called ‘project managers’ started appearing everywhere talking about ‘specs’ and ‘requirements gathering’. We tried and failed to rewrite our entire platform from scratch.

Yes, we were back to waterfall again, but this time the working cycles were faster and smaller, and the same problems of changing requirements and disputes with customers as before. So was it waterfall? We didn’t really know.

Collective Fictions in IT – Agile

I started hearing the word ‘Agile’ about 2003. Again, I don’t think I properly read up on it… ever, actually. I got snippets here and there from various websites I visited and occasionally from customers or evangelists that talked about it. When I quizzed people who claimed to know about it their explanations almost invariably lost coherence quickly. The few that really had read up on it seemed incapable of actually dealing with the very real pressures we faced when delivering software to non-sprint-friendly customers, timescales, and blockers. So we carried on delivering software with our specs, and some sprinkling of agile terminology. Meetings were called ‘scrums’ now, but otherwise it felt very similar to what went on before.

As a collective fiction it worked, because it kept customers and project managers off our backs while we wrote the software.

Since then I’ve worked in a company that grew to 700 people, and now work in a corporation of 100K+ employees, but the pattern is essentially the same: which incantation of the liturgy will satisfy this congregation before me?

Don’t You Believe?

I’m not going to beat up on any of these paradigms, because what’s the point? If software methodologies didn’t exist we’d have to invent them, because how else would we work together effectively? You need these fictions in order to function at scale. It’s no coincidence that the Agile paradigm has such a quasi-religious hold over a workforce that is immensely fluid and mobile. (If you want to know what I really think about software development methodologies, read this because it lays it out much better than I ever could.)

One of many interesting arguments in Sapiens is that because these collective fictions can’t adequately explain the world, and often conflict with each other, the interesting parts of a culture are those where these tensions are felt. Often, humour derives from these tensions.

‘The test of a first-rate intelligence is the ability to hold two opposed ideas in mind at the same time and still retain the ability to function.’ F. Scott Fitzgerald

I don’t know about you, but I often feel this tension when discussion of Agile goes beyond a small team. When I’m told in a motivational poster written by someone I’ve never met and who knows nothing about my job that I should ‘obliterate my blockers’, and those blockers are both external and non-negotiable, what else can I do but laugh at it?

How can you be agile when there are blockers outside your control at every turn? Infrastructure, audit, security, financial planning, financial structures all militate against the ability to quickly deliver meaningful iterations of products. And who is the customer here, anyway? We’re talking about the square of despair:

squareofdespair

When I see diagrams like this representing Agile I can only respond with black humour shared with my colleagues, like kids giggling at the back of a church.

AgileMotivationalPoster

When within a smaller and well-functioning functioning team, the totems of Agile often fly out of the window and what you’re left with (when it’s good) is a team that trusts each other, is open about its trials, and has a clear structure (formal or informal) in which agreement and solutions can be found and co-operation is productive. Google recently articulated this (reported briefly here, and more in-depth here).

So Why Not Tell It Like It Is?

You might think the answer is to come up with a new methodology that’s better. It’s not like we haven’t tried:

software-development-methods-explained-with-cars-toggl-infographic-02

It’s just not that easy, like the book says:

‘Telling effective stories is not easy. The difficulty lies not in telling the story, but in convincing everyone else to believe it. Much of history revolves around this question: how does one convince millions of people to believe particular stories about gods, or nations, or limited liability companies? Yet when it succeeds, it gives Sapiens immense power, because it enables millions of strangers to cooperate and work towards common goals. Just try to imagine how difficult it would have been to create states, or churches, or legal systems if we could speak only about things that really exist, such as rivers, trees and lions.’

Let’s rephrase that:

‘Coming up with useful software methodologies is not easy. The difficulty lies not in defining them, but in convincing others to follow it. Much of the history of software development revolves around this question: how does one convince engineers to believe particular stories about the effectiveness of requirements gathering, story points, burndown charts or backlog grooming? Yet when adopted, it gives organisations immense power, because it enables distributed teams to cooperate and work towards delivery. Just try to images how difficult it would have been to create Microsoft, Google, or IBM if we could only speak about specific technical challenges.’

Anyway, does the world need more methodologies? It’s not like some very smart people haven’t already thought about this.

Acceptance

So I’m cool with it. Lean, Agile, Waterfall, whatever, the fact is we need some kind of common ideology to co-operate in large numbers. None of them are evil, so it’s not like you’re picking racism over socialism or something. Whichever one you pick is not going to reflect the reality, but if you expect perfection you will be disappointed. And watch yourself for unspoken or unarticulated collective fictions. Your life is full of them. Like that your opinion is important. I can’t resist quoting this passage from Sapiens about our relationship with wheat:

‘The body of Homo sapiens had not evolved for [farming wheat]. It was adapted to climbing apple trees and running after gazelles, not to clearing rocks and carrying water buckets. Human spines, knees, necks and arches paid the price. Studies of ancient skeletons indicate that the transition to agriculture brought about a plethora of ailments, such as slipped discs, arthritis and hernias. Moreover, the new agricultural tasks demanded so much time that people were forced to settle permanently next to their wheat fields. This completely changed their way of life. We did not domesticate wheat. It domesticated us. The word ‘domesticate’ comes from the Latin domus, which means ‘house’. Who’s the one living in a house? Not the wheat. It’s the Sapiens.’

Maybe we’re not here to direct the code, but the code is directing us. Who’s the one compromising reason and logic to grow code? Not the code. It’s the Sapiens.

Currently co-authoring Second Edition of a book on Docker:

Get 39% off with the code 39miell2

dip

Advertisements

Rocket – A Rust game running on WASM

$
0
0

Two weeks ago, Alex Crichton’s PR adding a target for WebAssembly to the Rust compiler was merged. There are many differences between this target and the Emscripten one, but the important one for me is that it doesn’t depend on external stuff like the Emscripten SDK (which IIRC used to be a pain to get working on Windows, but seems to be better now).

After seeing the examples on hellorust.com, I thought it would be interesting to try to adapt my game Rocket to work on the browser through the wasm32-unknown-unknown target. The project was a great way to figure out how far you can go when porting a project that is a bit more complex than a hello world. I was pleasantly surprised by the fact that most of the code could be reused. Particularly, the game logic code was barely touched at all.

TLDR

Here is the source code. Also, you can play the game in the canvas below or on a dedicated tab.

The controls are:

  • Left and right arrows: turn left and right
  • Up arrow: boost
  • Space: shoot

An MVP

Getting things to compile: removing Piston

Before I started, the little I knew about WebAssembly was that it doesn’t allow you to interface with the OS, graphics card or other stuff like that. Using Emscripten seems to be a way around this problem, but I guess you still need to adapt your programs to some extent… I have never used it, though, so take my words with a grain of salt.

After cloning the Rocket repository I started removing stuff. The first thing to go was the dependency on Piston. I didn’t even try to compile Rocket to wasm before this step, as it is obvious that Piston requires OS support.

At this point, we were left with:

  1. No game loop
  2. No rendering
  3. No player input

Rebuilding the game: laying down the basic structure

So here we are without even a main function. This means that the game loop should be implemented in Javascript and call into our Rust functions. Therefore we need a set of basic functions that are enough to drive the execution of the game, draw something to the screen and process user input.

Since rendering and processing player input are more involved than just updating the game state, I chose the latter as a first function to implement. I was able to reuse the code for the game logic without any change, so the function ended up looking as follows:

#[no_mangle]pubextern"C"fn update(time: c_double) {let data:&mut GameData =&mut DATA.lock().unwrap();  data.time_controller.update_seconds(time, &data.actions, &mut data.state);  CollisionsController::handle_collisions(&mut data.state);}

Surprisingly, the update function on the original game is exactly the same, with the exception of the use of DATA. By the way, we use DATA to store state instead of passing it between Javascript and Rust every time we call a function. The definition is quite simple:

lazy_static! {staticref DATA: Mutex<GameData>= Mutex::new(new_game_data(1024.0, 600.0));}

Since DATA is accessible from anywhere in the program, Rust forces us to use a Mutex to ensure thread safety. Technically, this isn’t necessary in the case of Javascript, since there will only be one thread. Still, the type system knows nothing about that… Hence the mutex.

Getting things to compile, take two

With Piston out of the way, I set out to get the rest of the code to compile and to run it in the browser as a simulation without any visual output. This is the moment where difficulties started to pop out.

The first problem I encountered was caused by the dependency on rand. Generating random numbers doesn’t necessarily require OS support, but you need to generate a seed some way or another. For this reason, rand relies on an OsRng struct that is platform-dependent. Guess what… WebAssembly didn’t had such a struct, so the crate could not be compiled.

Fortunately, the problem was easily solved by adding such a struct. After patching the crate, the code finally compiled… but it didn’t run in the browser.

By the way, you are probably wondering about the seeding problem. If there is no way to communicate with the outside world from your WebAssembly programs, how can you get a seed? Below I will describe how you can call Javascript functions from Rust, which could be a solution to the problem. However, I decided to use a constant seed, which is clearly not optimal, but is good enough for a playable demo.

I mentioned in the paragraph above that the resulting program didn’t run on the browser. Concretely, after following the instructions on hellorust.com, I got the following error:

TypeError: import object field 'env' is not an Object

After looking around for a while, this turned out to be a linking problem. In other words, the generated Rust code contained calls to functions that didn’t exist. Therefore, the browser expected me to pass an import object containing said functions. It seems that some f64 functions I used in the physics part of the game have no analogous on WebAssembly, so I had to pass them explicitly from Javascript through the following object:

letimports={env:{Math_atan:Math.atan,sin:Math.sin,cos:Math.cos}};

After this, the code compiled and could be loaded on the browser, though without any kind of visual feedback. Rust running on the browser! Finally.

Making the game actually playable

Rendering

At this point I discovered that you could call Javascript functions from within the Rust program. This follows the same principle as using C functions from a library. On the Rust side, you need to declare the function as extern. On the Javascript side, you need to add the function to the imports, so it can be linked.

This means we can define drawing functions on the Javascript side and call them from Rust. Even though WebAssembly itself cannot interact with the outside world, it can still call Javascript functions you explicitly pass through the imports object. This will be our escape hatch to render the game to a canvas

Rendering things to the screen was as easy as adding a bunch of functions to my program:

extern"C" {fn clear_screen();fn draw_player(_: c_double, _: c_double, _: c_double);fn draw_enemy(_: c_double, _: c_double);fn draw_bullet(_: c_double, _: c_double);fn draw_particle(_: c_double, _: c_double, _: c_double);fn draw_score(_: c_double);}

Of course, these functions had to be implemented on the Javascript side. You can find them on the source code of the demo. You won’t find any surprises there, as the only thing they do is drawing to a canvas.

With these extern functions in place, I could implement the rest of the drawing code in Rust as shown below:

#[no_mangle]pubunsafeextern"C"fn draw() {use geometry::{Advance, Position};let data =&mut DATA.lock().unwrap();let world =&data.state.world;    clear_screen();for particle in&world.particles {        draw_particle(particle.x(), particle.y(), 5.0* particle.ttl);    }for bullet in&world.bullets {        draw_bullet(bullet.x(), bullet.y());    }for enemy in&world.enemies {        draw_enemy(enemy.x(), enemy.y());    }    draw_player(world.player.x(), world.player.y(), world.player.direction());    draw_score(data.state.score asf64);}

Again, if you compare this code to the original version, you will see that they are strikingly similar.

Processing user input

With simulation and rendering in place, enabling user input was almost trivial. First of all, I added a bunch of functions to toggle user actions on and off. Note that I am using a Rust type as a parameter of each function. This is technically incorrect, but I am not sure about which type I should use instead. If you do, please open a PR so it can be fixed.

#[no_mangle]pubextern"C"fn toggle_shoot(b:bool) {let data =&mut DATA.lock().unwrap();    data.actions.shoot = b;}#[no_mangle]pubextern"C"fn toggle_boost(b:bool) {let data =&mut DATA.lock().unwrap();    data.actions.boost = b;}#[no_mangle]pubextern"C"fn toggle_turn_left(b:bool) {let data =&mut DATA.lock().unwrap();    data.actions.rotate_left = b;}#[no_mangle]pubextern"C"fn toggle_turn_right(b:bool) {let data =&mut DATA.lock().unwrap();    data.actions.rotate_right = b;}

In this case, the code did differ considerably from the original version, since the latter relies on the piston_window::Key struct, which no longer exists. In the wasm version, I moved the key matching logic to Javascript, since I didn’t want to pass strings between Javascript and Rust. The resulting code is straightforward:

// Input processingfunctionprocessKey(key,b){switch(key){case"ArrowLeft":module.toggle_turn_left(b);break;case"ArrowRight":module.toggle_turn_right(b);break;case"ArrowUp":module.toggle_boost(b);break;case" ":module.toggle_shoot(b);break;}}document.addEventListener('keydown',e=>processKey(e.key,true));document.addEventListener('keyup',e=>processKey(e.key,false));

Even though the wasm32-unknown-unknown target is quite new, it clearly has a lot of potential. I am impressed by the fact that I was able to port Rocket with almost no modifications to the game logic code. In the end, I ended up spending most of the time dealing with rendering and figuring out how to correctly set up the integration between Javascript and Rust.

Back to posts

Theo de Raadt on integrating “safe” languages into OpenBSD

$
0
0
'Re: Integrating "safe" languages into OpenBSD?' - MARC
[prev in list] [next in list] [prev in thread] [next in thread] 
List:       openbsd-misc
Subject:    Re: Integrating "safe" languages into OpenBSD?
From:       "Theo de Raadt" <deraadt () openbsd ! org>
Date:       2017-12-03 20:37:07
Message-ID: 81638.1512333427 () cvs ! openbsd ! org
[Download message RAW]> As a response to this, Theo asked rhetorically "Where's ls, where's cat,> where's grep, and where's sort?", implying that noone so far bothered to> write implementations of even the basic unix utilities in such a> language.

I wasn't implying.  I was stating a fact.  There has been no attempt
to move the smallest parts of the ecosystem, to provide replacements
for base POSIX utilities.

As a general trend the only things being written in these new
languages are new web-facing applications, quite often proprietory or
customized to narrow roles.  Not Unix parts.

Right now, there are zero usage cases in the source tree to require
those compiler tools.  We won't put a horse into the source tree when
society lacks cart builders.

> This brings me to the question, what if someone actually bothered?

So rather than bothering to begin, you wrote an email.

Awesome.

Yes, now I am implying something: you won't bother to rewrite the
utilities.

And I understand, why would anyone bother?  It took about 10 years for
gnu grep to be replaced sufficiently well in our tree.  This stuff
doesn't happen overnight.

However there is a rampant fiction that if you supply a new safer
method everyone will use it.  For gods sake, the simplest of concepts
like the stack protector took nearly 10 years for adoption, let people
should switch languages?  DELUSION.

> Under what conditions would you consider replacing one of the> current C implementations with an implementation written in another,> "safer" language?

In OpenBSD there is a strict requirement that base builds base.

So we cannot replace any base utility, unless the toolchain to build
it is in the base.  Adding such a toolchain would take make build time
from 40 minutes to hours.  I don't see how that would happen.

> Note that with Cgrep and haskell-ls, there do in fact exist> implementations/analogues of two of the mentioned utilities in a> memory safe language (Haskell).

Are they POSIX compliant?  No.  They are completely different programs
that have borrowed the names.

By the way, this is how long it takes to compile our grep:

    0m00.62s real     0m00.63s user     0m00.53s system

Does Cgrep compile in less than 10 minutes?

Such ecosystems come with incredible costs.  For instance, rust cannot
even compile itself on i386 at present time because it exhausts the
address space.

Consider me a skeptic -- I think these compiler ecosystems face a grim
bloaty future.

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About |News |Add a list | Sponsored by KoreLogic

Workshop Report: Hi-Perf ClojureScript with WebGL, Asm.js and Emscripten (2016)

$
0
0

The majority of Clojurescript application development and community discussions seems to be focused on improving standard UI implementation patterns and the general workflow of how we can build web applications better, easier and faster. In this respect it’s been truly amazing to observe how much has been achieved in so short time (especially over the past 2 years) and I think by now Clojurescript and the tooling enabled by it, really does offer an outstanding, simple and largely joyful web development experience. Since the language is mainly targeting the browser environment, it’s maybe also about time to become an ever more attractive choice for building apps utilizing the full feature set of what the modern browser environment offers and here I’m thinking mainly about applications going beyond those usually built with Clojurescript thus far. When it comes to working with features like WebGL, WebAudio, WebRTC, WebWorkers, building data and graphics intensive, visualization related or generally highly interactive and media rich web applications, games etc., Clojurescript tooling / library support and feasibility suddenly have been still questionable and it’s something myself (and others) have been actively working on to fix over the past few years. The primary approach to work with these features then has been via existing Javascript libraries, often requiring large amounts of interop code and having to deal with issues that don’t fit that nicely with the Clojurescript modus operandi.

Most applications related to graphics involve a large amount of heavy data processing and transformations in the browser, much more so than in the typical, more or less form-driven web app scenario, however glitzy it might look & feel. Performance matters a great deal in this context, since we too have a hard time limit for this processing to keep the UI and/or animation fluid and responsive at preferably 60fps. So for this workshop I chose to look more below the surface of Clojurescript, analyze problem areas, examine possible optimization strategies and above all introduce people to a number of modern web technologies (WebGL, WebRTC, WebWorkers, Emscripten), techniques & tools offering possible routes to use the language in a sound and elegant way to work with these features.

Slow life vs Fast life

For the first exercise we looked at the classic Game of Life (GOL) simulation and undertook a series of six optimization steps to speed it up by a factor of 650, compared to the original and most idiomatic implementation. The GOL is great context for exploring a variety of language constructs and patterns, from data structures, iteration, sequence processing and JS interop required to visualize the simulation state. Its evaluation process is a 3x3 kernel based matrix convolution and therefore much of the approaches here also apply to other related use cases (e.g. adjacency matrices (graphs), image processing, machine learning etc.)

Workshop exercise #1: Six implementations of Conway’s Game of Life — from naive (but idiomatic & slow) to optimized Clojurescript using typed arrays and direct pixel manipulations (10,840 ms / frame vs 16.5 ms / frame = ~650x faster for a 1024x1024 grid). Live demo

When it comes to optimization, there are generally two prevailing camps: Optimize Early and Optimize Late, with the latter being the by far larger group, and both having good arguments for their case. The main arguments used by the Optimize Late crowd are that optimized code is harder to read, harder to maintain, less flexible, often contains bugs and above all that it’s often only 10% of a code base which drastically impact performance. On the other hand, the Optimize Early crowd argues that the slow 10% in reality never exist in isolation, are scattered around, hard to find and hence optimizing them usually is limited to piecewise micro-optimizations and therefore requires a large amount of refactoring and re-testing, all of which can be avoided by simply being more aware of performance critical sections during the design and implementation. For them, it’s a matter of better understanding language constructs, algorithms and how the machine actually operates and therefore write more efficient (rather than just functional/working) code in the first place. System response times are/should be part of the design spec and been given time budgets, as e.g. is often done in game development and embedded software with hard real time limitations. We can’t argue that this is a bad thing, can we? (Just for the record, I’m trying not to be ignorant of either way and unconsciously aim for an happy compromise between these polar extremes)

With this in mind, as part of this first exercise we looked at:

Awareness & understanding overheads of idiomatic language patterns

The textbook approach to encoding a 2D data grid in Clojure/script is using a nested vector, which then can easily be processed using map / reduce to produce the next generation in the simulation. Accessing individual grid cells is also straightforward using (get-in grid [x y]). However, in the GOL simulation we need to access 9 cells (1 cell + 8 neighbors) in order to compute the new state of each cell. So in a 1024 x 1024 grid this use of get-in will result in the creation of 9,437,184 temporary Clojurescript vector objects (the vectors for the lookup coordinates) per frame, exercising a huge pressure on the garbage collector. In addition, since get-in can take lookup paths of any length and works polymorphically using protocol methods, each invocation also incurs a call to reduce, resulting in even more temp objects, an iteration loop and a load of protocol dispatch functions for its internal use of get — altogether a lot of (way too much!) work for a simple 2D index lookup.

In some situations (only if the lookup path is static, as in our case), we could write a macro version of get-in, expanding the lookup calls at compile time and thereby removing at least the overhead of a vector allocation and the use of reduce at runtime:

Benchmarking this example with criterium under Clojure (which has somewhat different/faster protocol dispatch than in Clojurescript), the macro version results in 43.61ns vs 205.18ns for the default get-in (~5x faster).

Often these things are relegated as micro-optimizations and in some ways they are, but considering that core functions like get-in are heavily used throughout most Clojurescript applications, being more aware of the inherent costs is useful and can help us looking into alternative solutions when needed.

Btw. One of the intermediate steps taken to speed up our simulation was using transduce instead of map& reduce to compute the number of alive neighbor cells, however this ended up actually being ~15–20% slower in this case. We have not looked into the reasons for this (yet)…

Persistent vs mutable datastructures

The more obvious improvement to speed up the simulation was using a flat 1D vector to encode the grid and calculate cell indices for the 2D coordinates, much like in a pixel buffer. This not just gives us better cache locality, but instead of get-in we could now just use nth, gain a ~6x speed up and somewhat simpler code.

The final step (leaving out some other stages) of this exercise was an introduction to JS Typed Arrays, creating typed views over byte buffers and updating the canvas not via its 2D drawing API, but making use of direct pixel manipulations via the canvas context’s ImageData. Since all our data (both simulation grid and pixels) are stored in typed arrays, we switched to only use loop instead of map / reduce (thereby removing millions of internal function calls) and altogether gained a ~650x speedup compared to the original.

A live version of the exercise is here: http://demo.thi.ng/ws-ldn-8/gol/ (Please be aware that the UI for the “naive” mode and largest grid size will completely freeze for ~10 seconds)

Some of the other things we talked about:

  • avoid keywords or collections as functions (use get instead)
  • use named functions instead of closures for map/reduce fns
  • protocol function dispatch overhead
  • loop vs doseq
  • deftype vs. defrecord (code size, memory efficiency, protocols)
  • controlled use of set! and volatile! to achieve mutability

WebGL

To anyone interested in directly utilizing the GPU in the browser, WebGL is a huge & fascinating topic, but it can also be very daunting for newcomers to graphics programming, since efficient use of it requires a multitude of prerequisite knowledge and terminology about 2D/3D geometry, linear algebra, spatial thinking in multiple spaces (coordinate systems), low-level data organization, the OpenGL state machine (with 100’s of options), GPU processing pipelines, knowledge of the GLSL shading language, color theory etc. Not all of it has to do with actual coding and it’s often the theory moments when A-level maths knowledge comes back knocking on our door — it’s a lot to take in, especially in a 3-day workshop, but we tried to cover most of the core topics (and altogether probably spent most of the time on that) and we put theory to practical use with the help of various thi.ng/geom examples. Later on we walked through an early prototype for a WebGL game written in Clojurescript, going into more advanced topics, incl. creating mesh geometries from scratch and creating a path-following camera etc.

Live demo of the game “prototype” (just a POC really thus far): http://demo.thi.ng/sjo/ — Move mouse to move horizontally in the tunnel, press/hold down to accelerate (also works with touch) — The entire tunnel is generated using the Cinquefoil Knot formula and Parallel-Transport frames to create the polygon segments. Btw. Sjö = Seven in Islandic

thi.ng/geom is the most mature of the thi.ng projects and has had basic WebGL support for over 2 years, however only recently I’ve managed to invest more time in extending and updating its API to provide an unified solution for both desktop OpenGL & WebGL in the browser. Some of the latest additions include:

The thi.ng/geom library takes a semi-declarative approach to working with OpenGL/WebGL in that it’s extensively using Clojure maps to define various geometry and shader specifications, which are then compiled into the required data buffers & GLSL programs. This approach helps to make data manipulations easier and avoids (for most common use cases) the direct use of WebGL function calls in user code. Where possible, to make shader re-use easier between OpenGL 3.x/4.x & WebGL (which have some syntax differences), shader specs specify their global variables (attributes, uniforms, varyings) as Clojure maps which are then translated into the correct GLSL syntax using automatic code generation/injection before compilation. In general the library does offer a number of helpers & abstractions over the WebGL internals, but at no point is it hiding the underlying layer, giving advanced users full control over the GL state machine.

Texture mapping & color blend equation example
Render-to-texture and multi-pass FX processing to create classic Bloom effect for bright image areas
Obligatory globe demo, explaining how different geometries require different types of texture mapping

Using WebGL with Reagent / React.js

Since a WebGL app usually wants to update its visualization as often as possible, it doesn’t directly map to the worldview of React. For this purpose, I’ve been defining a little reusable canvas component for Reagent and most of the later workshop examples made use of it:

Managing GLSL shader dependencies

Code re-use is one of the big issues with GLSL (on any platform) and for a long time this has been largely solved via a copy & paste culture. To address this in Clojurescript from early on, we can use the thi.ng/shadergraph library, which provides us with:

  • a transitive dependency resolution mechanism for GLSL code (based on the normal Clojure namespace mechanism and Stuart Sierra’s dependency library)
  • a growing library of pure, commonly used GLSL functions (lighting, color conversion, matrix math, rotations, effects etc.). Shader snippets can be defined via Clojure strings or loaded from separate source files (as part of the Clojurescript compilation process).
  • a basic compile-time shader minifier
  • Clojure meta data extraction of the defined GLSL functions (incl. arg lists and return type for improved REPL use and in preparation of future tooling)

Many of the workshop examples utilize various functions provided by this library and helped us getting results faster.

WebRTC & video FX processing

Since some of the participants were interested in using video for their own projects, I prepared a small example combining a WebRTC camera stream with Shadertoy-like WebGL image processing using a bunch of effect options.

https://github.com/thi-ng/ws-ldn-8/tree/master/day3/ex06

Yours truly testing out a cheesy twirl video effect — Online demo unavailable due to current lack of SSL, which is required for WebRTC.

Web workers

Since 2013 Clojurescript has been blessed with the core.async library, providing us (among many super useful CSP abstractions) with the illusion of concurrent processes in the inherently single-threaded environment of the JS VM. However, the currently only way to obtain real extra compute resources of a multi-core CPU in JavaScript is to use WebWorkers and their use is one of the not-so-widely talked about topics in the Clojurescript community. For one, they’re not the same as multi-threading in Clojure, and furthermore, their use throws several spanners in the works, both in terms of Clojurescript (+Figwheel) workflow, but also due to their inherent limitation of running in an isolated environment from the main application.

WebWorker code needs to be loaded from a separate source file and can only communicate with the main process via message passing. By default, the data passed to the other process is copied, but some types (e.g. ArrayBuffers) can also be transferred and when doing so the sender process loses ownership/access. For large (binary) data this can be very useful though (e.g. any use case which allows for typed arrays) and is potentially magnitudes faster than using a copy. The most likely scenario for this transfer feature is a ping-pong like processing setup of the same data object between main process and worker, each claiming temporary ownership rights before sending it back to the other party. Rust users might feel right at home here :)

In terms of code organization, Clojurescript’s (well, actually Google Closure compiler’s) modular compilation at least allows us to keep the worker parts in the same code base without incurring another copy of compiled Clojurescript. The bad news are, that modular compilation is currently not supported when using the build profile “:optimizations :none”, as is usually the case during development. One way to workaround this is by trying to isolate the development of the worker in time (do it first), compile it and then use Figwheel (or similar) for working on the main app.

Our little example project can be found here:

https://github.com/thi-ng/ws-ldn-8/tree/master/day3/ex06

asm.js & Emscripten

Even though thi.ng started out as (and largely still is) a Clojure & Clojurescript-centric collection of projects, over the past year I’ve been slowly expanding its scope to become more polyglot, so far mainly in the form of some still unreleased C projects (not counting previous OpenCL related thi.ngs). And whilst the combination of Clojure/Clojurescript + C seems a bit weird at first, I’m fully convinced (and have proof!) there are many use cases for which I believe this combination is golden, giving us the best of both worlds: one of the currently best approaches and workflows to build the high-level aspects of an app and at the same time benefit from much better performance and more efficient memory usage for the parts where it matters most. This is especially true for Clojurescript, which is becoming ever more important for my line of work and in some ways makes it much easier to integrate foreign C modules than with its JVM-based parent.

Simple 3D particle system written in C, compiled to Javascript with Emscripten and visualized / controlled via Clojurescript & WebGL. Live demo

One of the most interesting projects in this respect is Emscripten, a LLVM-based transpiler for C and C++ to asm.js (and soon WASM). The former (asm.js) is a highly optimizable subset of JavaScript. WASM (WebAssembly) is a new sandboxed execution environment currently still being designed as an open standard by a W3C Community Group that includes representatives from all major browsers. Even though Emscripten’s current output isn’t really native code, it allows us to write code in C, which for some use cases (e.g. math heavy code, mutable data structures, WebGL, DSP etc.) is much easier to write than in Clojurescript and in my own tests the resulting asm.js code almost always performs noticeably faster than the Clojurescript version (even if the latter is compiled w/ Closure compiler’s advanced optimizations). With WebAssembly on the horizon, it’s maybe a good time to invest some time into some “upskilling” (or down-skilling, as in low-level)…

For the final exercise of the workshop we implemented a simple 3D particle system in C, compiled it with Emscripten and learned how to integrate it into a Clojurescript WebGL demo. This exercise tied up many of the things (and loose ends) from the past days and too allowed me once more to demonstrate the efficient use of typed arrays for visualization purposes.

The above C structs are used for our particle system. The Emscripten runtime emulates the C heap as a single, large JS ArrayBuffer with multiple views of various word sizes (using typed arrays of uint8, uint16, uint32, float32 etc.). Therefore a C pointer is simply an index into this array buffer and with a bit of planning we can directly make use of this from the Clojurescript side to avoid copying large amounts of data, something which would cause a huge overhead and make the whole exercise of using C/asm.js pointless…

The diagram below shows the memory layout of the ParticleSystem’s “particles” array. Each particle only takes up 36 bytes (much less than we could idiomatically achieve in Clojurescript) and since that’s a multiple of 4, all particles in this array are tightly packed and no alignment bytes are needed (Floats always need to be stored at 4-byte boundaries).

On the Clojurescript side we’re using Reagent to wrap React.js and the latest dev snapshot (0.0.1158-SNAPSHOT) of thi.ng/geom to handle all WebGL aspects.

Thanks to Emscripten’s interop API, communication between the compiled C module and CLJS is pretty trivial, even though we’re limited to only passing/receiving primitive LLVM data types. In the case of our example this is absolutely fine though, since in CLJS we’re only interested in a) initializing the particle system, b) updating it and c) obtaining a pointer to the array of particles. The following code shows how to wrap and call compiled C functions from Clojurescript:

Updating and rendering the particle system with WebGL is similarly trivial. After each update of the system, we also must update the buffer data for WebGL and for this we simply reference the memory in the C heap array. Our shader only requires the particle position and color attributes, both of which are part of the same chunk of memory and stored in an interleaved manner. When setting up the WebGL buffers, we only need to supply the correct stride length (36 bytes, see above diagram) and for the color attribute we too need to adjust the data offset of 24 bytes (equivalent of 6 floats into the array).

The full source code for this example is here: https://github.com/thi-ng/ws-ldn-8/tree/master/day3/ex07

Outlook & Near future

If you’re interested in learning more about any of these technologies, please visit the workshop.thi.ng website for upcoming training sessions or sign up to the thi.ng newsletter.

I’m about to announce the next bunch of workshop dates for June in the next 2 days. Apart from teaching, I’m also currently available for freelance consulting. Please get in touch and let’s talk, no agents though! Thanks.

The Icelandic translation of Dracula is actually a different book

$
0
0

The Icelandic version of Dracula is called Powers of Darkness, and it’s actually a different—some say better—version of the classic Bram Stoker tale.

Makt Myrkranna (the book’s name in Icelandic) was "translated" from the English only a few years after Dracula was published on May 26, 1897, skyrocketing to almost-instant fame. Next Friday is still celebrated as World Dracula Day by fans of the book, which has been continuously in print since its first publication, according to Dutch author and historian Hans Corneel de Roos for Lithub. But the Icelandic text became, in the hands of translator Valdimar Ásmundsson, a different version of the story.

The book’s Icelandic text was unknown to English-speaking aficionados of the Dark Prince until recently, de Roos writes, as no one had bothered to re-translate it back into English. Although Dracula scholars knew about the existence of Powers of Darkness as far back as 1986, they didn’t know it was actually a different story. Then, he writes, “literary researcher Richard Dalby reported on the 1901 Icelandic edition and on its preface, apparently written specifically for it by Stoker himself.”

The preface was what got English-language scholars interested in the Icelandic book, but still, nobody thought to compare the actual text of Makt Myrkranna to the original Stoker novel, assuming, as Dalby wrote, that it was “merely an abridged translation of Dracula,” de Roos writes. Finally in 2014, de Roos writes that he went back to the original text of Powers of Darkness to verify something, and discovered that the Icelandic story diverged from the English original.

As de Roos worked on the translation, patterns emerged: many of the characters had different names, the text was shorter and had a different structure, and it was markedly sexier than the English version, he writes. It's also, he writes, better:  "Although Dracula received positive reviews in most newspapers of the day...the original novel can be tedious and meandering....Powers of Darkness, by contrast, is written in a concise, punchy style; each scene adds to the progress of the plot."

“The nature of the changes has led de Roos to argue that they could not have been the work of Valdimar alone,” according toIceland Magazine. “Instead he has speculated that Valdimar and Stoker must have collaborated in some way. Stoker could, for example, have sent Valdimar an older version of his story.”

Like any good Gothic story, though, the mystery doesn’t end there. Makt Myrkanna was originally published in serial form in an Icelandic newspaper in 1901. Many scholars, including de Roos, believed it was one of the first translations and serializations of Stoker’s 1897 novel. But recent publicity surrounding the Icelandic text, which was published in translation only a month ago, prompted a Swedish scholar to reveal that there was an 1899 Swedish translation of the book, according to the Iceland Monitor.

The new version, which scholars think was the version that Powers of Darkness was based on, means there’s more digging still to do before the true history of Dracula is revealed. 

Like this article?
SIGN UP for our newsletter


The attack of the SuperFakes

$
0
0

S

even years ago, watch fan Andrew Dakin bought a Movado watch on eBay for $500. It looked like a mint timepiece, well-maintained and classically styled. He had just started collecting watches, so he was happy to get a deal on a unique and valuable timepiece.

“At that point I was probably like 30 watches in so I thought I knew what I was doing,” said Dakin, describing his early collecting experiences.

Many first-time collectors like to create huge collections of watches, picking up cheaper pieces to get a feel for the market. This Movado was something special, however. It was made by a classic maker made famous by their ultra-minimalist Museum watch, a piece featuring a dot, a noon and nothing else. The watch arrived in the mail and it looked legitimate. He wore it for a while and then took it to a jeweler to see how much it would be worth if he cleaned it up and resold it.

The jeweler took the watch to the back of the shop and came back upset.

It was a fake. A very good fake.

Ebay and other online markets have always trafficked in fakes. From fake memory cards to swap meet Louis it’s hard for the average online consumer to tell if they are buying real products and often they don’t care. But in the case of watches like Movado, Omega and Rolex, it’s getting harder to tell the real from the replica and the stakes are surprisingly high.

“I would have worn and eventually sold it thinking it was real had I never compared to a real one,” said Dakin. He was impressed.

“Once you see a good fake it’s actually scary to think about how many people are walking around with a fake watch that they think is real and they will sell or pass down to someone thinking it’s real,” he said.

Fake watches have always plagued the horological arts. But these fakes – created so that they can sell for a maximum price to unsuspecting buyers – are getting better and better. In fact, the Movado Dakin bought seven years ago was probably far from the best available fake on the market.

Welcome to the strange world of SuperFakes, a new breed of fake watch that, thanks to advances in manufacturing and 3D printing, are often indistinguishable from the real thing. Fakers make these pieces for pennies and can sell them for thousands, often duping first-time collectors and experienced resellers with their high-quality creations.

Fakes have been around as long as watches have graced the pockets and wrists of folks who would pay for them. In the 1800s, boulevardiers considered American watches made by Hampden and Elgin to be the best in the world. Made in bulk using new machining techniques, American watches beat Swiss and French pieces in quality and reliability. Swiss watchmakers found themselves at a loss. They depended on untrained laborers and older milling and cutting machinery, and they found their pieces were getting steadily worse.

Swiss watchmakers had a plan, however. They would use American techniques to create exact copies of American watches.

The most frequently duplicated pieces were popular “railroad watches,” the saucer-sized pocket watches carried by old-timey train conductors. Rather than copy the pieces wholesale, the Swiss depended on marketing slight of hand to sell their wares: They changed popular brand names slightly to avoid detection and simply sold them alongside the superior American pieces. Illinois-made Elgin became the Swiss-made Elfin. Marion Watch Company became Marvin (which, in turn, investors revived as a luxury brand in the 21st century), and “A.W.W.Co” became “B.W.W.Co.”. These fakes, far from being the worst of the lot, were designed to copy the superior American wares in every way.

This habit fell away as Switzerland caught up with and surpassed American manufacturers. Now, however, it’s the Swiss suffering from the same fake fate that befell the American brands.

The fakes industry – created as a reaction to the changes in engineering techniques in the 18th and 19th centuries – resurfaced in the 20th century when watchmakers began selling luxury watches made of steel and brands like Rolex gained prominence. Because it was far easier to fake a watch in plain metal than in a gold, Canal Street in New York became a veritable wholesale market for fake Presidents and Daytonas. Many of these reproductions were laughably bad with poorly placed logos, fake chronograph pushers, and even quartz movements in watches that were supposed to be completely mechanical and “hand made.” But that didn’t stop buyers from snapping up these “faux-lexes” as status symbols.

These obvious fakes have slowly given way to fakes that are so uniquely well-made that they are almost indistinguishable from the real thing.

The Federation of the Swiss Watch industry says Switzerland produces 30 million watches a year. They estimate that fakers build 1.6 million a year, ensuring that your chances of finding a fake in the wild are fairly high. The new manufacturing technologies that make it easier for Chanel to make ceramic cases make it easy for fakers to produce something similar, if not identical, to the real thing. It is trivial to get these fakes from the factory to the street, leading to a flood of fake watches that are almost indistinguishable from real watches to the average consumer.

Hamilton Powell sees the flood of SuperFakes almost every day. His company, Crown & Caliber, specializes in reselling pre-owned watches. Owners send in their watches for appraisal and receive a check. Crown & Caliber’s in-house watchmakers clean and regulate the pieces and then sell them to collectors who want a deal on popular pieces like Rolex Submariners, Omega Speedmasters, and Panerai Submersibles. The company has processed 15,000 fine watches and has seen hundreds of fakes.

“Historically, less than 5 percent of the watches that we authenticate are fake,” said Powell. “At one point this number was as high as 10 percent.” However, the numbers are growing.

Powell is pragmatic about the fakes market. It’s inevitable.

“E-commerce has been a blessing and a curse,” he said. “The blessing? The world is at your fingertips, and we can now find and receive goods faster than ever before. With that, there are legitimate resale platforms out there, making it easy to find and access a wide selection of luxury timepieces. These sites have built their business on authentication and quality. However, there is a market of people who are selling fake goods passed off as real.

“Technology advancements and access are the culprits. To start, access to high-tech machinery is more prevalent than ever,” he continued. “So, what could have been a rare or cost-prohibitive piece of equipment is now available to more people.”

F

akes come in all shapes and sizes. Rolex is the most faked with copies of Submariner, Daytona and Datejust appearing regularly. Breitling and Omega are next with Super Avenger, and the Seamaster fakes hitting the market daily. Interestingly, fakers have copied almost every Panerai model thanks to the simplicity of the watch. In fact, fakers have copied many of the specific Panerai hallmarks, including specially designed internal parts designed to prevent faking.

“Panerai SuperFakes are some of the best out there given the minimalism on the dials,” said Powell.

These watch brands are entry-level in the strange and pricey Pantheon of luxury watches. However, said Powell, less popular and more expensive makers like Chopard, Piaget and Hublot are seeing fakes hit the market, a testament to the broad popularity of once-exclusive watch models. While actually quite difficult, fakers spend extra time and money on creating realistic SuperFakes because the stakes are so high.

Emma Monks, head of social media risk at Crisp, a brand-safety adviser, says that fakes worth “nearly half a trillion dollars” hit the market yearly.

“It’s not just an issue of hitting the luxury brand’s bottom line, though. The reputational damage and loss of consumer trust are massive problems,” she said. “Counterfeits are often of inferior quality leading to, at best, an influx of customer complaints and, at worst, injury from dangerous fakes. If the buyer believed the product they bought to be genuine, even after they approach the brand and discover it’s a fake, the lingering bad taste from the experience can sour their trust and appreciation of the brand.”

In other words, fakers can make thousands of dollars on a good fake rather than a few dollars on an obvious fake. In fact there is an entire world of ”replica watches” that sell many exact copies of popular watches. This strange underworld is similar to the replica car market where fans buy supercars for $20,000 because they are “reskinned” Toyota Camrys and Corollas.

These replicas live in the murky world of dedicated fandom if you can convince an eBay buyer that the Rolex they are buying is authentic a $300 replica turns into a $5,000 jackpot.

“The high price-point of luxury is what appeals to these counterfeit craftsmen,” said Powell. “They can make a lot of money without a lot of investment into each piece.”

Thanks to a rise in the vintage market, fakers can also turn old watches into Rolexes and Omegas by replacing parts like faces, hands and movements. In fact, some fakers create real-looking parts on authentic equipment, a wild extravagance that is well worth the time and effort. Some fakers also create frankenwatches, pieces that use real parts to create a watch that is more valuable and collectable than the original piece.

“When a brand hits a rough patch, they will sometimes sell off some of their equipment,” said Powell. “This allows people to create inauthentic parts made on authentic machines.”

How do fakers make these watches so realistic? They begin by choosing an easily reproducible design. Take these Panerai Luminors, for example. The real model, on the right, would be indistinguishable from the fake on the left to the untrained eye. The font and hand style look quite similar and only small clues – the thickness of the hands, the quality of the illumination – would give away the trick.

The trouble continues inside these pieces. In the photo above, the piece on the right is the fake. Compare it to the more austere but real movement on the left. The fake movement, a copy of the Unitas 6497, has been engraved with repeating logos and “beautified” with a few unique additions to an otherwise generic movement.

This exuberant modification is designed to through the unwary off the trail. After all, a storied watchmaker like Panerai wouldn’t put such a boring movement into a $10,000 watch… or would it?

T

echnologies like 3D printing are improving fake manufacturing, as well. While not everything can be 3D-printed, metal sintering and CNC machines let fakers create unique cases using powerful, high-resolution 3D printers. But there is still a great deal that needs to change in order for fakers to truly 3D print fake pieces.

“SLS type of metal parts are too porous and have a matte finish,” said Jon Buford, a 3D printing expert in Hong Kong. “For the most part, the precision isn’t there for the feature size. You are probably more likely to be able to do a micro-CNC (subtractive) type of process to make things and have the same output as the traditional processes. Another possibility would be to do additive 3D printing process and then do precision subtractive processes to clean them up.”

High end fakers aren’t just effecting watchmakers, however. Fakers are taking the tricks they learned in manufacturing to other products. A few months ago Benjamin Saks of Kerfcase needed a copy of an iPhone X to test a new case model. They visited the web and found just the thing.

“Since apple announced in September but the iPhone X didn’t drop till November This gave us a lot of time to look at the drawings and photos of the phone, but I really wanted one in the shop to test,” he said. “I had looked around on the typical places. Alibaba and AliExpress have shady dummy phones, in bulk, but it’s always a crapshoot. I thought, hey, Amazon has everything. Literally. Maybe not for the best price, but it was worth a shot. So I did a simple search for ‘dummy iPhone’ and found this.”

It was a near perfect replica of an iPhone made with extremely high-quality components.

“It has a steel plate inside the injection-molded ABS frame. There is glass on the front and back (thin) and buttons with de-dents so they click. The port has nothing in it, and the speakers also are just holes. A close inspection would let you figure out it is a fake, but if left on the bar at your favorite watering hole, it would for sure get swiped,” he said.

“It is incredible that a whole industry exists to make products like this. The quality of the molds is very high – ejector pins are clean, seams are tight and the hand assembly that has to be done is amazing for something that likely costs a few bucks to manufacture.”

This frustrates everyone in the manufacturing industry.

“Detecting and combating counterfeiters is not easy,” said Monks. “Many are operating out of countries where prosecution may be impossible, and that gives them the confidence to flaunt their products on image-driven social platforms such as Instagram. Taking action against their accounts is digital whack-a-mole; the counterfeiter generally has dozens more accounts already created and ready to activate in order to avoid disruption to their trade.”

Ultimately these fakes end up hurting consumers and forces makers to dedicate precious resources to fake reduction rather than innovation. As wristwatches fall in popularity there is less to be made in the luxury watch market, making it all the more important for storied brands to fight back against fakes.

Whether or not you see the value in buying a $12,000 watch that can be faked for $5, watchmaking is a rapidly diminishing art and watchmakers are slowly leaving the field, disheartened by consumers who are happy to tote around a $300 fake Rolex over a real piece with history, provenance, and quality. Still, sometimes fakes make it through to consumers who end up disappointed that their amazing watch isn’t quite as amazing as they thought.

“We offer all of our customers an ‘out’ – we send them an empathetic email apologizing for having to be the bearer of bad news that the watch they sent us was a replica, we don’t use the word fake,” said Powell. “Most of these people never contact us back. The ones who do are generally really embarrassed and apologetic because they had no idea.”

Unsupervised Image-To-Image Translation Networks

$
0
0

Unsupervised image-to-image translation aims at learning a joint distribution of images in different domains by using images from the marginal distributions in individual domains. Since there exists an infinite set of joint distributions that can arrive the given marginal distributions, one could infer nothing about the joint distribution from the marginal distributions without additional assumptions. To address the problem, we make a shared-latent space assumption and propose an unsupervised image-to-image translation framework based on Coupled GANs. We compare the proposed framework with competing approaches and present high quality image translation results on various challenging unsupervised image translation tasks, including street scene image translation, animal image translation, and face image translation. We also apply the proposed framework to domain adaptation and achieve state-of-the-art performance on benchmark datasets.

Did American Missile Defense Fail in Saudi Arabia?

$
0
0

The official story was clear: Saudi forces shot down a ballistic missile fired by Yemen’s Houthi rebel group last month at Saudi Arabia’s capital, Riyadh. It was a victory for the Saudis and for the United States, which supplied the Patriot missile defense system.

“Our system knocked the missile out of the air,” President Trump said the next day from Air Force One en route to Japan, one of the 14 countries that use the system. “That’s how good we are. Nobody makes what we make, and now we’re selling it all over the world.”

But an analysis of photos and videos of the strike posted to social media suggests that story may be wrong.

Instead, evidence analyzed by a research team of missile experts appears to show the missile’s warhead flew unimpeded over Saudi defenses and nearly hit its target, Riyadh’s airport. The warhead detonated so close to the domestic terminal that customers jumped out of their seats.

Estimated trajectory

of warhead

Trajectory of

missile body

The warhead appeared to explode near an airport terminal.

The missile body

landed downtown.

Estimated trajectory

of warhead

Trajectory of

missile body

The warhead appeared to explode near an airport terminal.

The missile body

landed downtown.

Estimated trajectory

of warhead

Trajectory of

missile body

The warhead appeared to explode near an airport terminal.

The missile

body landed downtown.

Estimated trajectory

of warhead

Trajectory of

missile body

The warhead appeared to explode near an airport.

The missile body landed downtown.

Satellite image from DigitalGlobe via Google Earth

Saudi officials did not respond to a request for comment. Some U.S. officials cast doubt on whether the Saudis hit any part of the incoming missile, saying there was no evidence that it had. Instead, they said, the incoming missile body and warhead may have come apart because of its sheer speed and force.

The findings show that the Iranian-backed Houthis, once a ragtag group of rebels, have grown powerful enough to strike major targets in Saudi Arabia, possibly shifting the balance of their years-long war. And they underscore longstanding doubts about missile defense technology, a centerpiece of American and allied national defense strategies, particularly against Iran and North Korea.

“Governments lie about the effectiveness of these systems. Or they’re misinformed,” said Jeffrey Lewis, an analyst who led the research team, which shared its findings with The New York Times. “And that should worry the hell out of us.”

The Missile

Shooting down Scud missiles is difficult, and governments have wrongly claimed success against them in the past.

The missile, seen in this video released by the Houthis, is believed to be a Burqan-2, a variant of the Scud missile used throughout the Middle East. It traveled about 600 miles.

Saudi and American officials have accused Iran of supplying the Houthis with the missile, a charge that Tehran denies. A recent United Nations report found evidence that the missile had been designed and manufactured by Iran, according to a Security Council diplomat. Reuters first reported the U.N. findings.

Mr. Lewis and the other analysts, based mostly at the Middlebury Institute of International Studies in Monterey, Calif., were skeptical when they heard Saudi Arabia’s claim to have shot it down.

Governments have overstated the effectiveness of missile defenses in the past, including against Scuds. During the first Gulf War, the United States claimed a near-perfect record in shooting down Iraqi variants of the Scud. Subsequent analyses found that nearly all the interceptions had failed.

Had it failed in Riyadh as well? The researchers scraped social media for anything posted in that area and time frame, looking for clues.

The Debris

The pattern of missile debris littering Riyadh suggests missile defenses either hit the harmless rear section of the missile or missed it entirely.

Just as the Saudis fired off missile defenses, debris began to fall in downtown Riyadh. Video posted on social media captured one particularly large section, which landed in a parking lot next to the Ibn Khaldun School.

Other videos show scraps that fell at a handful of other locations clustered in a roughly 500-yard area along a highway.

Saudi officials said the debris, which appears to belong to a downed Burqan-2, showed a successful shootdown. But an analysis of the debris shows that the warhead components – the part of the missile that carries the explosives – were missing.

Composite image by Jeffrey Lewis

The missing warhead signaled something important to the analysts: that the missile may have evaded Saudi defenses.

The missile, in order to survive the stresses of a roughly 600 mile flight, was almost certainly designed to separate into two pieces once near its target. The tube, which propels the missile for most of its trajectory, falls away. The warhead, smaller and harder to hit, continues toward the target.

Warhead was missing

from debris

Warhead was missing

from debris

Warhead was missing

from debris

This would explain why the debris in Riyadh only appears to consist of the rear tube. And it suggests that the Saudis may have missed the missile, or only hit the tube after it had separated and begun to fall uselessly toward earth.

Some U.S. officials said there was no evidence the Saudis had hit the missile. Instead, the debris may have broken up under the pressures of flight. What the Saudis presented as evidence of their successful interception may have simply been the missile ejecting its tube as intended.

The Location of the Explosion

A blast 12 miles away at Riyadh’s airport suggests the warhead continued unimpeded toward its target.

At around 9 p.m., about the same time debris crashed in Riyadh, a loud bang shook the domestic terminal at Riyadh’s King Khalid International Airport.

“There was an explosion at the airport,” a man said in a video taken moments after the bang. He and others rushed to the windows as emergency vehicles streamed onto the runway.

Another video, taken from the tarmac, shows the emergency vehicles at the end of the runway. Just beyond them is a plume of smoke, confirming the blast and indicating a likely point of impact.

A Houthi spokesman said the missile had targeted the airport.

There’s another reason the analysts think the warhead flew past the missile defenses. They located the Patriot batteries that fired on the missile, shown in this video, and found that the warhead traveled well over the top of them.

Saudi officials have said that some debris from the intercepted missile landed at the airport. But it is difficult to imagine how one errant piece could fly 12 miles beyond the rest of the debris, or why it would detonate on impact.

The warhead passed over the Saudi missile defense unit.

Estimated trajectory of warhead

Estimated trajectory

of missile body

The warhead passed over the Saudi missile defense unit.

Estimated trajectory of warhead

Estimated trajectory

of missile body

Trajectories estimated by David Wright, Union of Concerned Scientists

The Impact

Smoke and ground damage suggest the warhead struck near the airport’s domestic terminal.

Imagery of the emergency response and a plume of smoke also reveal information about the nature of the impact.

A photo of the plume taken from a different location on the tarmac appears consistent with plumes produced by similar missiles, suggesting the explosion was not an errant piece of debris or an unrelated incident.

Riyadh airport

Daraya, Syria

By identifying buildings in the photo and video, Mr. Lewis’s team was able to locate the spots from which the images were taken, revealing the precise location of the plume: a few hundred yards off of runway 33R, and about a kilometer from the crowded domestic terminal.

King Khalid

International Airport

Emergency vehicles seen on runway

Dark areas indicate

ground damage

from vehicles

Emergency vehicles

seen on runway

Dark areas indicate

ground damage

from vehicles

King Khalid

International Airport

Emergency vehicles seen on runway

Dark areas indicate

ground damage

from vehicles

The blast was small, and satellite imagery of the airport taken immediately before and after the blast is not detailed enough to capture the crater from the impact, the analysts said.

But it does show ground damage from the emergency vehicles, supporting the finding that the warhead hit just off the runway.

While the Houthis missed their target, Mr. Lewis said, they got close enough to show that their missiles can reach it and can evade Saudi defenses. “A kilometer is a pretty normal miss rate for a Scud,” he said.

Even the Houthis may not have realized their success, Mr. Lewis said. Unless they had intelligence sources at the airport, they would have little reason to doubt official reports.

“The Houthis got very close to creaming that airport,” he said.

Laura Grego, a missile expert at the Union of Concerned Scientists, expressed alarm that Saudi defense batteries had fired five times at the incoming missile.

"You shoot five times at this missile and they all miss? That's shocking,” she said. “That's shocking because this system is supposed to work.”

Justin Kan’s Atrium is starting a boot camp to help founders raise money

$
0
0

Raising a Series A is hard for a founder. Especially when you consider they’re usually doing it for the first time, while the VCs on the other side of the table are essentially professional negotiators getting pitched and doing deals every day.

So to help give founders a leg up Justin Kan’s new legal tech startup Atrium is launching a program to help founders become better fundraisers.

Called Atrium Academy, the free two-day program pairs new founders with seasoned entrepreneurs and VCs to learn best tips on negotiation, building demand and a narrative and raising in general. It’s almost like YC’s startup school, but instead of bringing in enterprising students and convincing them to start a company Atrium is bringing in established companies and helping them raise a Series A or first major round of funding.

The startup ran a trial program last month and had 130 applications that were whittled down to 12 founders from around the world who flew in for the program. While there’s no set number of how many the program will accept, Kan made it clear that founders had to be running successful companies that was on track to soon raise a round.

Accepted founders were able to spend time in office hours with VCs from firms like Accel, General Catalyst and Initialized Capital and also see presentations and fireside talks from entrepreneurs who have had success raising Series A rounds.

Startups also were able to meet with Atrium’s lawyers for counseling and legal preparation specifically for the financing process. All attendees also receive discounted legal services if they choose to use Atrium as their law firm. Of course some may say that this is all just a lead generation tactic to get more companies using Atrium as their lawyer when they decide to raise a Series A.

Kan didn’t totally dismiss this idea – instead saying that it’s more realistically “very indirect lead generation”. Certaintly Atrium won’t be able to sign up all of these companies – some may already have lawyers from a seed round, and other may never end up raising or just decide not to use Atrium. But Kan sees the program as a great way to build goodwill for his company while at the same time getting to help the startup ecosystem in general, regardless of how much direct payback it results in.

Atrium plans on hosting four batches a year going forward, with the first being January 18th, 2017. Applications are open now.

Malware Detection in Executables Using Neural Networks

$
0
0

Malware detection.The detection of malicious software (malware) is an increasingly important cyber security problem for all of society. Single incidences of malware can cause millions of dollars in damage. The current generation of anti-virus and malware detection products typically use a signature-based approach, where a set of manually crafted rules attempt to identify different groups of known malware types. These rules are generally specific and brittle, and usually unable to recognize new malware even if it uses the same functionality.

This approach is insufficient because most environments have unique binaries that will have never been seen before and millions of new malware samples are found every day. The need to develop techniques that can adapt to the rapidly changing malware ecosystem is seemingly a perfect fit for machine learning. Indeed, a number of startups and established cyber-security companies have started building machine learning based systems. These companies typically spend considerable effort in feature engineering and analysis to build high quality systems. But what if we could build an anti-virus system without any feature engineering? That could allow the same system to detect malware across a variety of operating systems and hardware. We demonstrate a significant step towards this goal in our most recent research paper.

CREDIT: The work and paper described in this blog post was completed in collaboration with Edward Raff, Jared Sylvester, Robert Brandon and Charles Nicholas who collectively represent the Laboratory for Physical Sciences, Booz Allen Hamilton and University of Maryland, Baltimore County, in addition to Bryan Catanzaro who leads the NVIDIA Applied Deep Learning Research Team.

The paper introduces an artificial neural network trained to differentiate between benign and malicious Windows executable files with only the raw byte sequence of the executable as input. This approach has several practical advantages:

  • No hand-crafted features or knowledge of the compiler used are required. This means the trained model is generalizable and robust to natural variations in malware.
  • The computational complexity is linearly dependent on the sequence length (binary size), which means inference is fast and scalable to very large files.
  • Important sub-regions of the binary can be identified for forensic analysis.
  • This approach is also adaptable to new file formats, compilers and instruction set architectures—all we need is training data.

We also hope this paper demonstrates that malware detection from raw byte sequences has unique and challenging properties that make it a fruitful research area for the larger machine learning community.

Challenges in Applying Deep Learning to Malware Detection

One reason for the recent success in applying neural networks to computer vision, speech recognition and natural language processing is their ability to learn features from raw data such as pixels or individual text characters. Inspired by these successes, we wanted to see if a neural network could be trained on just the raw bytes of an executable file to determine if the file is malware. If we could achieve this, we may be able to greatly simplify the tools used for malware detection, improve detection accuracy and identify non-obvious but important features exhibited by malware.

However, there exist a number of challenges and differences in the malware domain that have not been encountered in other deep learning tasks. For Microsoft Windows Portable Executable (PE) malware, these challenges include:

  • Treating each byte as a unit in an input sequence means we are dealing with a sequence classification problem on the order of two million time steps. To our knowledge, this far exceeds the length of input to any previous neural-network-based sequence classifier.
  • The bytes in malware can have multiple modalities of information. Any particular byte taken in context could be encoding human-readable text, binary code, or arbitrary objects such as images and more. Furthermore, some of this content may be encrypted and essentially random to the neural network.
  • The contents of a binary at the function level can be arbitrarily re-arranged with little effort, but there is complicated spatial correlation across functions due to function calls and jump commands.

Little work has been done on sequence classification at the scale explored in this paper. Audio is the closest domain in pure sequence length. A state of the art network such as WaveNet uses raw bytes of audio as it’s input and target, but this still only results in a sequence analysis problem with tens of thousands of steps—two orders of magnitude smaller compared to our malware detection problem.

Sequences in the millions of steps present significant practical challenges when used as the input to a neural network with parameter choices in the ranges commonly used in natural language processing and audio processing. Principle among these is the memory footprint of the activations between layers in the network. For example, if the raw bytes of a two-million-step sequence were represented using a 300-dimensional trainable embedding layer in 32-bit floating point that input would immediately require nearly 2.4 GB of memory.  If it were then passed into a length-preserving 1D convolution layer with filter size 3 and 128 filters, the activations of that one layer alone would require another 1GB of memory. Remember that this is for a single input sequence to a single layer, not a minibatch as is commonly used in neural network training.

Breaking down the sequence into subsequences processed individually won’t work either as the indicators of malware can be sparse and distributed throughout the file, so there is no way to map global labels for a training file to subsequences without introducing an overwhelming amount of noise. Furthermore, having only one label for all two million time steps of an input sequence with sparse discriminative features makes for an extremely challenging machine learning problem due to a very weak training signal.

Our Solution

We experimented with a large number of different neural network architectures for this problem. The challenges outlined above led us to try to some unusual architectures and parameter choices. The search for better-performing architectures required balancing increasing the number of trainable parameters in the model with keeping the memory footprint of the activations small enough to allow a large enough mini-batch size to be used so that training times were practical and training converged.

When designing the model we aimed for three features:

  1. the ability to scale efficiently in computation and memory usage with sequence length
  2. the ability to consider both local and global context while examining the entire file, and
  3. an explanatory ability to aid analysis of flagged malware.
Figure 1. Architecture of the malware detection network.
Figure 1. Architecture of the malware detection network.

In the end, the best performing model is certainly atypical in its small number of trainable parameters (134,632) and shallow architecture. Figure 1 shows a block diagram of this model.

We were able to achieve 1) while maximizing the network’s number of trainable parameters by using a gated convolution architecture and a trainable embedding vector representation of the input bytes. In the gated architecture, for each convolution layer there is a second parallel convolution layer with sigmoid activation.  The elementwise product of the outputs of these two parallel layers is passed to the reLU non-linearity.  This enables the sigmoid convolution layer to filter the information allowed out of the reLU convolution layer, which adds additional capacity to the model’s feature representations in an efficient way.

We controlled the memory footprint of the convolution layer activations using aggressive striding and large convolutional filter sizes. Intuitively, it seems like these choices would degrade model accuracy, however we found in our experiments that finer convolutions and smaller striding did not lead to a better performing architecture.

We achieved 2) by following the convolutional layer with global max pooling. One way to interpret the function of this network is that the gated convolutional layer is able to recognize local indicators of malware and the max pooling followed by fully connected layer assesses the relative strength of those indicators throughout the file and recognizes significant global combinations.

A consistent result across tested architectures is a propensity for overfitting. This is not surprising given the large input feature space from which we must learn the benign/malicious classification using a single loss. We found that penalizing the correlation between hidden state activations at the fully connected layer, as described in [Cogswell et al. 2016], to be the most effective form of regularization. Intriguingly, we found that the commonly used batch-normalization actually prevented our models from converging and generalizing. See Section 5.3 of the paper for further discussion on why this might be the case.

Data and Training

We used two datasets to train and validate this network. We collected the first set, Group A, from publicly available sources. The benign data came from a clean installation of Microsoft Windows with some commonly installed applications and the malware came from the VirusShare corpus. Group A contains 43,967 malicious and 21,854 benign files. The second set, Group B, was provided by an industry anti-virus partner with both benign and malicious files representative of files seen on real machines in the wild. Group B contains 400,000 unique files split evenly between benign and malicious classes. Group B also includes a test set of 74,349 files of which 40,000 are malicious and the remainder benign.

We found that training on Group A results in severe overfitting, resulting in models that learn to recognize “from Microsoft” instead of “benign”. A model trained on Group A does not generalize to Group B. However, we found that a model trained on Group B does generalize to Group A. Therefore we performed our experiments by training on Group B and testing on both Group A and the Group B test set. Testing in this manner allows us to better quantify generalizability as the data are from different sources. We consider Group A’s test performance as most interesting because the data has the fewest common biases with Group B, although we want our model to have similar performance on both test sets to indicate the features learned are widely useful.

In addition, late in our experimentation we received a larger training corpus from the same source as Group B containing 2,011,786 unique binaries with 1,011,766 malicious files.

In order to get model convergence in a timely manner it was essential to train the network using a large batch size. Due to the extreme memory usage of the network activations this necessitated the use of data parallel model training. We were able to train this model on the 400,000-sample Group B training set using data parallelism across eight GPUs of a DGX-1 in about 16.75 hours per epoch, for 10 epochs, and using all available GPU memory. Training on the larger two-million-sample set took one month on the same system.

Results

The most pertinent metric in evaluating the performance of our model is AUC. This is due to the need to perform malware triage where a queue of binaries is created for quarantine and manual analysis based on a priority scoring. A high AUC score (close to 1) corresponds to successful ranking of most malware above most benign files. It is critical to achieve this high AUC because manual analysis of a single binary by an expert malware analyst can take in excess of 10 hours. AUC also has the benefit of allowing us to compare performance across our two test datasets with differing numbers of benign and malicious samples.

Table 1 shows the performance of our model compared to the best performing models already in the literature. The first of those models uses raw byte n-grams as the input features to a logistic regression model [Raff et al. 2016]. The second model applies a shallow fully-connected neural network to byte n-grams taken from the file PE-Header only [Raff et al. 2017].  Table 1 shows the best results in bold.

Table 1: Performance of malware detection models on Group A and Group B test sets when trained on both the small (400,000 samples) and large (two million samples) Group B training sets.
Train setTest setOur model AUCByte n-grams AUCPE-Header Network
Group B train (small)Group A98.598.497.7
Group B train (small)Group B test95.897.991.4
Group B train (large)Group A98.193.4
Group B train (large)Group B test98.297.0

Looking at the results, you can see that our model is best for Group A and second best for Group B. However, when we train using the larger corpus of 2 million files we find that our model continues to improve, becoming the best performing model on both test sets, whilst the performance of the byte n-gram model actually degrades.  This indicates a brittleness and propensity to overfit in the byte n-gram model.

Practical Applicability

In the paper we additionally report the balanced test accuracy of the models in our experiments, that is their ability to differentiate benign and malware files with equal importance given to each. While our model performs favorably under this metric it is not necessarily indicative of model performance in real-world conditions. There are a variety of use cases for a malware detection system. For high-volume triage of files, throughput is king, meaning that there may be a lower tolerance for false alarms. In other settings false alarms may be acceptable in return for high sensitivity; in other words, true malware is rarely missed.

In either case, the result of a detection will be some form of more detailed analysis of the potential malware, often by an expert malware analyst. We wanted to ensure our network has some ability to explain its classification decisions to help focus the attention and time of an analyst. We did this by taking inspiration from the class activation map (CAM) technique of [Zhou et al. 2016]. For each of the classes benign and malware we produce a map of the relative contribution of each filter at its most active application location in the convolution layer. You can think of this as identifying which regions contribute most to the benign or malware classification. We call our modification sparse-CAM because using global max pooling rather than average pooling leads to a naturally sparse activation map. Figure 2 illustrates sparse-CAM.

Figure 2. Sparse-CAM explanatory mechanism.
Figure 2. Sparse-CAM explanatory mechanism.

Previous work showed that the byte n-gram model obtained almost all of its discriminative information from the header of the executable file. This means that byte n-gram models do not typically use the actual executable code or data sections of the file as discriminative features. The results in Table 1 show that, in our tests, models that have access to the entire executable file achieve higher classification accuracy than those that are restricted to just the file header.

Analysis of the sparse-CAM for 224 randomly selected binaries by an expert malware analyst revealed that our model had 39-42% of it’s most important features located outside of the file header. In particular we saw indications of both executable code and data containing discriminative features.

Table 2: Important features by file section, as determined by the non-zero regions of the sparse-CAM mapped to the output of the PE-file.
SectionTotalPE-Header.rsrc.textUPX1CODE.data.rdata.reloc
Malicious26,23215,8713,3152,878697615669383214
Benign19,29011,1832,6532,41459650542324377

Conclusion

This paper shows that neural networks are capable of learning to discriminate benign and malicious Windows executables without costly and unreliable feature engineering.  This avoids a number of issues with commonly used anti-virus and malware detection systems while achieving higher classification AUC.

A byte-level understanding of programs could have many applications beyond malware classification, such as static performance prediction and automated code generation. But progress towards that goal will require critical thinking about ways to reduce the memory intensity of this problem and about what types of neural network architectural designs may allow us to better capture the multiple modes of information represented in a binary.

We hope that this work encourages the broader machine learning community to explore malware detection as a fruitful area for research due to its unique challenges, such as extremely long sequences and sparse training signal. Deep Learning has enjoyed some spectacular success and advancement thanks to applications in image, signal and natural language processing. Expanding to a radically different domain like malware detection has already helped us better understand some of the aspects of our tooling and learning methods that don’t trivially transfer to new data and problem domains, such as batch normalization. It also gives a further glimpse into how widely applicable neural networks can be.

Please download the paper from Arxiv now and come hear us present this work at the AAAI 2018 Artificial Intelligence for Cyber Security workshop.

References

[Cogswell et al. 2016] Reducing Overfitting in Deep Networks by Decorrelating Representations, Cogswell, M.; Ahmed, F.; Girshick, R.; Zitnick, L.; and Batra, D. (ICLR 2016) https://arxiv.org/abs/1511.06068

[Zhou et al. 2016] Learning Deep Features for Discriminative Localization. Zhou, B.; Khosla, A.; Lapedriza, A.; Oliva, A.; and Torralba, A. (CVPR 2016) https://arxiv.org/abs/1512.04150

[Raff et al. 2016] An investigation of byte n-gram features for malware classification. Raff, E.; Zak, R.; Cox, R.; Sylvester, J.; Yacci, P.; Ward, R.; Tracy, A.; McLean, M.; and Nicholas, C. Journal of Computer Virology and Hacking Techniques. 2016

[Raff et al. 2017] Learning the PE Header, Malware Detection with Minimal Domain Knowledge, Raff, E.; Sylvester, J.; and Nicholas, C. arXiv:1709.01471, 2017

Viewing all 25817 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>